home *** CD-ROM | disk | FTP | other *** search
/ AGA Toolkit '97 / The AGA Toolkit '97.iso / programming / e / beginnersguide / beginner.txt < prev    next >
Encoding:
Text File  |  1996-09-07  |  291.0 KB  |  7,397 lines

  1. Copyright (c) 1994, Jason R. Hulance
  2.  
  3.  
  4. A Beginner's Guide to Amiga E
  5. *****************************
  6.  
  7.    This Guide gives an introduction to the Amiga E programming language
  8. and, to some extent, programming in general.
  9.  
  10. Contents
  11. --------
  12.  
  13. Part One:    Getting Started
  14.  
  15.   Introduction to Amiga E  
  16.   Understanding a Simple Program  
  17.   Variables and Expressions  
  18.   Program Flow Control  
  19.   Summary  
  20.  
  21. Part Two:    The E Language
  22.  
  23.   Format and Layout  
  24.   Functions  
  25.   Constants  
  26.   Types  
  27.   More About Statements and Expressions  
  28.   E Built-In Constants Variables and Functions  
  29.   Modules  
  30.   Exception Handling  
  31.   Recursion  
  32.  
  33. Part Three:  Worked Examples
  34.  
  35.   Introduction to the Examples  
  36.   Timing Expressions  
  37.   Argument Parsing  
  38.   Gadgets IDCMP and Graphics  
  39.   Recursion Example  
  40.  
  41. Part Four:   Appendices
  42.  
  43.   Common Problems  
  44.   New Features  
  45.   Syntax Description  
  46.   Other Information  
  47.  
  48. ========================================================================
  49.  
  50.  
  51. Introduction to Amiga E
  52. ***********************
  53.  
  54.    To interact with your Amiga you need to speak a language it understands.
  55. Luckily, there is a wide choice of such languages, each of which fits a
  56. particular need.  For instance, BASIC (in most of its flavours) is simple
  57. and easy to learn, and so is ideal for beginners.  Assembly, on the other
  58. hand, requires a lot of effort and is quite tedious, but can produce the
  59. fastest programs so is generally used by commercial programmers.  These
  60. are two extremes and most businesses and colleges use C or
  61. Pascal/Modula-2, which try to strike a balance between simplicity and
  62. speed.
  63.  
  64.    E programs look very much like Pascal or Modula-2 programs, but E is
  65. based more closely on C. Anyone familiar with these languages will easily
  66. learn E, only really needing to get to grips with E's unique features and
  67. those borrowed from other languages.  This guide is aimed at people who
  68. haven't done much programming and may be too trivial for competent
  69. programmers, who should find the `E Reference Manual' more than adequate.
  70.  
  71.    Part One (this part) goes through some of the basics of the E language
  72. and programming in general.  Part Two delves deeper into E, covering the
  73. more complex topics and the unique features of E. Part Three goes through
  74. a few example programs, which are a bit longer than the examples in the
  75. other Parts.  Finally, Part Four contains the Appendices, which is where
  76. you'll find some other, miscellaneous information.
  77.  
  78. Next:
  79.  
  80.   A Simple Program  
  81.  
  82. ========================================================================
  83.  
  84.  
  85. A Simple Program
  86. ================
  87.  
  88.    If you're still reading you're probably desperate to do some
  89. programming in E but you don't know how to start.  We'll therefore jump
  90. straight in the deep end with a small example.  You'll need to know two
  91. things before we start: how to use a text editor and the Shell/CLI.
  92.  
  93. Next:
  94.  
  95.   The code  
  96.   Compilation  
  97.   Execution  
  98.  
  99. ========================================================================
  100.  
  101.  
  102. The code
  103. --------
  104.  
  105.    Enter the following lines of code into a text editor and save it as the
  106. file simple.e (taking care to copy each line accurately).  (Just type the
  107. characters shown, and at the end of each line press the RETURN or ENTER
  108. key.)
  109.  
  110.      PROC main()
  111.        WriteF('My first program')
  112.      ENDPROC
  113.  
  114. Don't try to do anything different, yet, to the code: the case of the
  115. letters in each word is significant and the funny characters are important.
  116. If you're a real beginner you might have difficulty finding the '
  117. character.  On my GB keyboard it's on the big key in the top left-hand
  118. corner directly below the ESC key.  On a US and most European keyboards
  119. it's two to the right of the L key, next to the ; key.
  120.  
  121. ========================================================================
  122.  
  123.  
  124. Compilation
  125. -----------
  126.  
  127.    Once the file is saved (preferably in the RAM disk, since it's only a
  128. small program), you can use the E compiler to turn it into an executable
  129. program.  All you need is the file ec in your C: directory or somewhere
  130. else on your search path (advanced users note: we don't need the Emodules:
  131. assignment because we aren't using any modules).  Assuming you have this
  132. and you have a Shell/CLI running, enter the following at the prompt after
  133. changing directory to where you saved your new file:
  134.  
  135.      ec simple
  136.  
  137. If all's well you should be greeted, briefly, by the E compiler.  If
  138. anything went wrong then double-check the contents of the file simple.e,
  139. that your CLI is in the same directory as this file, and that the program
  140. ec is in your C: directory (or on your search path).
  141.  
  142. ========================================================================
  143.  
  144.  
  145. Execution
  146. ---------
  147.  
  148.    Once everything is working you can run your first program by entering
  149. the following at the CLI prompt:
  150.  
  151.      simple
  152.  
  153.    As a help here's the complete transcript of the whole compilation and
  154. execution process (the CLI prompt, below, is the bit of text beginning
  155. with 1. and ending in >):
  156.  
  157.      1.Workbench3.0:> cd ram:
  158.      1.Ram Disk:> ec simple
  159.      Amiga E Compiler/Assembler/Linker v2.1b (c) 91/92/93 $#%!
  160.      lexical analysing ...
  161.      parsing and compiling ...
  162.      no errors
  163.      1.Ram Disk:> simple
  164.      My first program1.Ram Disk:>
  165.  
  166. Your display should be something similar if it's all worked.  Notice how
  167. the output from the program runs into the prompt (the last line).  We'll
  168. fix this soon.
  169.  
  170. ========================================================================
  171.  
  172.  
  173. Understanding a Simple Program
  174. ******************************
  175.  
  176.    To understand the example program we need to understand quite a few
  177. things.  The observant amongst you will have noticed that all it does is
  178. print out a message, and that message was part of a line we wrote in the
  179. program.  The first thing to do is see how to change this message.
  180.  
  181. Next:
  182.  
  183.   Changing the Message  
  184.   Procedures  
  185.   Parameters  
  186.   Strings  
  187.   Style Reuse and Readability  
  188.   The Simple Program  
  189.  
  190. ========================================================================
  191.  
  192.  
  193. Changing the Message
  194. ====================
  195.  
  196.    Edit the file so that line contains a different message between the two
  197. ' characters and compile it again using the same procedure as before.
  198. Don't use any ' characters except those around the message.  If all went
  199. well, when you run the program again it should produce a different message.
  200. If something went wrong, compare the contents of your file with the
  201. original and make sure the only difference is the message between the '
  202. characters.
  203.  
  204. Next:
  205.  
  206.   Tinkering with the example  
  207.   Brief overview  
  208.  
  209. ========================================================================
  210.  
  211.  
  212. Tinkering with the example
  213. --------------------------
  214.  
  215.    Simple tinkering is a good way to learn for yourself so it is
  216. encouraged on these simple examples.  Don't stray too far, though, and if
  217. you start getting confused return to the proper example pretty sharpish!
  218.  
  219. ========================================================================
  220.  
  221.  
  222. Brief overview
  223. --------------
  224.  
  225.    We'll look in detail at the important parts of the program in the
  226. following sections, but we need first to get a glimpse of the whole
  227. picture.  Here's a brief description of some fundamental concepts:
  228.  
  229.    *     Procedures: We defined a procedure called main and used the
  230.      (built-in) procedure WriteF.  A procedure can be thought of as a
  231.      small program with a name.
  232.  
  233.    *     Parameters: The message in parentheses after WriteF in our
  234.      program is the parameter to WriteF.  This is the data which the
  235.      procedure should use.
  236.  
  237.    *     Strings: The message we passed to WriteF was a series of
  238.      characters enclosed in ' characters.  This is known as a string.
  239.  
  240. ========================================================================
  241.  
  242.  
  243. Procedures
  244. ==========
  245.  
  246.    As mentioned above, a procedure can be thought of as a small program
  247. with a name.  In fact, when an E program is run the procedure called main
  248. is executed.  Therefore, if your E program is going to do anything you
  249. must define a main procedure.  Other (built-in or user-defined) procedures
  250. may be run (or called) from this procedure (as we did WriteF in the
  251. example).  For instance, if the procedure fred calls the procedure barney
  252. the code (or mini-program) associated with barney is executed.  This may
  253. involve calls to other procedures, and when the execution of this code is
  254. complete the next piece of code in the procedure fred is executed (and
  255. this is generally the next line of the procedure).  When the end of the
  256. procedure main has been reached the program has finished.  However, lots
  257. can happen between the beginning and end of a procedure, and sometimes the
  258. program may never get to finish.  Alternatively, the program may crash,
  259. causing strange things to happen to your computer.
  260.  
  261. Next:
  262.  
  263.   Procedure Definition  
  264.   Procedure Execution  
  265.   Extending the example  
  266.  
  267. ========================================================================
  268.  
  269.  
  270. Procedure Definition
  271. --------------------
  272.  
  273.    Procedures are defined using the keyword PROC, followed by the new
  274. procedure's name (in lowercase letters), a description of the parameters
  275. it takes (in parentheses), a series of lines forming the code of the
  276. procedure and then the keyword ENDPROC.  Look at the example program again
  277. to identify the various parts.  See The code.
  278.  
  279. ========================================================================
  280.  
  281.  
  282. Procedure Execution
  283. -------------------
  284.  
  285.    Procedures can be called (or executed) from within the code part of
  286. another procedure.  You do this by giving its name, followed by some data
  287. in parentheses.  Look at the call to WriteF in the example program.  See
  288. The code.
  289.  
  290. ========================================================================
  291.  
  292.  
  293. Extending the example
  294. ---------------------
  295.  
  296.    Here's how we could change the example program to define another
  297. procedure:
  298.  
  299.      PROC main()
  300.        WriteF('My first program')
  301.        fred()
  302.      ENDPROC
  303.      
  304.      PROC fred()
  305.        WriteF('...slightly improved')
  306.      ENDPROC
  307.  
  308. This may seem complicated, but in fact it's very simple.  All we've done
  309. is define a second procedure called fred which is just like the original
  310. program--it outputs a message.  We've called this procedure in the main
  311. procedure just after the line which outputs the original message.
  312. Therefore, the message in fred is output after this message.  Compile the
  313. program as before and run it so you don't have to take my word for it.
  314.  
  315. ========================================================================
  316.  
  317.  
  318. Parameters
  319. ==========
  320.  
  321.    Generally we want procedures to work with particular data.  In our
  322. example we wanted the WriteF procedure to work on a particular message.
  323. We passed the message as a parameter (or argument) to WriteF by putting it
  324. between the parentheses (the ( and ) characters) that follow the procedure
  325. name.  When we called the fred procedure, however, we did not require it
  326. to use any data so the parentheses were left empty.
  327.  
  328.    When defining a procedure when define how much and what type of data we
  329. want it to work on, and when calling a procedure we give the specific data
  330. it should use.  Notice that the procedure fred (like the procedure main)
  331. has empty parentheses in its definition.  This means that the procedure
  332. cannot be given any data as parameters when it is called.  Before we can
  333. define our own procedure that takes parameters we must learn about
  334. variables.  We'll do this in the next chapter.  See
  335. Global and local variables.
  336.  
  337. ========================================================================
  338.  
  339.  
  340. Strings
  341. =======
  342.  
  343.    A series of characters between two ' characters is known as a string.
  344. Almost any character can be used in a string, although the \ and '
  345. characters have a special meaning.  For instance, a linefeed is denoted by
  346. the two characters \n.  We now know how to stop the message running into
  347. the prompt.  Change the program to be:
  348.  
  349.      PROC main()
  350.        WriteF('My first program\n')
  351.        fred()
  352.      ENDPROC
  353.      
  354.      PROC fred()
  355.        WriteF('...slightly improved\n')
  356.      ENDPROC
  357.  
  358. Compile it as before, and run it.  You should notice that the messages now
  359. appear on lines by themselves, and the second message is separated from
  360. the prompt which follows it.  We have therefore cured the linefeed problem
  361. we spotted earlier (see Execution).
  362.  
  363. ========================================================================
  364.  
  365.  
  366. Style, Reuse and Readability
  367. ============================
  368.  
  369.    The example has grown into two procedures, one called main and one
  370. called fred.  However, we could get by with only one procedure:
  371.  
  372.      PROC main()
  373.        WriteF('My first program\n')
  374.        WriteF('...slightly improved\n')
  375.      ENDPROC
  376.  
  377.    What we've done is replace the call to the procedure fred with the code
  378. it represents (this is called inlining the procedure).  In fact, almost
  379. all programs can be easily re-written to eliminate all but the main
  380. procedure.  However, splitting a program up using procedures normally
  381. results in more readable code.  It is also helpful to name your procedures
  382. so that their function is apparent, so our procedure fred should probably
  383. have been named message or something similar.  A well-written program in
  384. this style can read just like English (or the any other spoken language).
  385.  
  386.    Another reason for having procedures is to reuse code, rather than
  387. having to write it out every time you use it.  Imagine you wanted to print
  388. the same, long message fairly often in your program--you'd either have to
  389. write it all out every time, or you could write it once in a procedure and
  390. call this procedure when you wanted the message printed.  Using a
  391. procedure also has the benefit of having only one copy of the message to
  392. change, should it ever need changing.
  393.  
  394. ========================================================================
  395.  
  396.  
  397. The Simple Program
  398. ==================
  399.  
  400.    The simple program should now (hopefully) seem simple.  The only bit
  401. that hasn't been explained is the built-in procedure WriteF.  E has many
  402. built-in procedures and later we'll meet some of them in detail.  The
  403. first thing we need to do, though, is manipulate data.  This is really
  404. what a computer does all the time--it accepts data from some source
  405. (possibly the user), manipulates it in some way (possibly storing it
  406. somewhere, too) and outputs new data (usually to a screen or printer).
  407. The simple example program did all this, except the first two stages were
  408. rather trivial.  You told the computer to execute the compiled program
  409. (this was some user input) and the real data (the message to be printed)
  410. was retrieved from the program.  This data was manipulated by passing it
  411. as a parameter to WriteF, which then did some clever stuff to print it on
  412. the screen.  To do our own manipulation of data we need to learn about
  413. variables and expressions.
  414.  
  415. ========================================================================
  416.  
  417.  
  418. Variables and Expressions
  419. *************************
  420.  
  421.    Anybody who's done any school algebra will probably know what a
  422. variable is--it's just a named piece of data.  In algebra the data is
  423. usually a number, but in E it can be all sorts of things (e.g., a string).
  424. The manipulation of data like the addition of two numbers is known as an
  425. expression.  The result of an expression can be used to build bigger
  426. expressions.  For instance, 1+2 is an expression, and so is 6-(1+2).  The
  427. good thing is you can use variables in place of data in expressions, so if
  428. x represents the number 1 and y represents 5, then the expression y-x
  429. represents the number 4.  In the next two sections we'll look at what kind
  430. of variables you can define and what the different sorts of expressions
  431. are.
  432.  
  433. Next:
  434.  
  435.   Variables  
  436.   Expressions  
  437.  
  438. ========================================================================
  439.  
  440.  
  441. Variables
  442. =========
  443.  
  444.    Variables in E can hold many different kinds of data (called types).
  445. However, before a variable can be used it must be defined, and this is
  446. known as declaring the variable.  A variable declaration also decides
  447. whether the variable is available for the whole program or just during the
  448. code of a procedure (i.e., whether the variable is global or local).
  449. Finally, the data stored in a variable can be changed using assignments.
  450. The following sections discuss these topics in slightly more detail.
  451.  
  452. Next:
  453.  
  454.   Variable types  
  455.   Variable declaration  
  456.   Assignment  
  457.   Global and local variables  
  458.   Changing the example  
  459.  
  460. ========================================================================
  461.  
  462.  
  463. Variables types
  464. ---------------
  465.  
  466.    In E a variable is a storage place for data (and this storage is part
  467. of the Amiga's RAM).  Different kinds of data may require different
  468. amounts of storage.  However, data can be grouped together in types, and
  469. two pieces of data from the same type require the same amount of storage.
  470. Every variable has an associated type and this dictates the maximum amount
  471. of storage it uses.  Most commonly, variables in E store data from the
  472. type LONG.  This type contains the integers from -2,147,483,648 to
  473. 2,147,483,647, so is normally more than sufficient.  There are other
  474. types, such as INT and LIST, and more complex things to do with types, but
  475. for now knowing about LONG is enough.
  476.  
  477. ========================================================================
  478.  
  479.  
  480. Variable declaration
  481. --------------------
  482.  
  483.    Variables must be declared before they can be used.  They are declared
  484. using the DEF keyword followed by a (comma-separated) list of the names of
  485. the variables to be declared.  These variables will all have type LONG
  486. (later we will see how to declare variables with other types).  Some
  487. examples will hopefully make things clearer:
  488.  
  489.      DEF x
  490.      
  491.      DEF a, b, c
  492.  
  493. The first line declares the single variable x, whilst the second declares
  494. the variables a, b and c all in one go.
  495.  
  496. ========================================================================
  497.  
  498.  
  499. Assignment
  500. ----------
  501.  
  502.    The data stored by variables can be changed and this is normally done
  503. using assignments.  An assignment is formed using the variable's name and
  504. an expression denoting the new data it is to store.  The symbol :=
  505. separates the variable from the expression.  For example, the following
  506. code stores the number two in the variable x.  The left-hand side of the
  507. := is the name of the variable to be affected (x in this case) and the
  508. right-hand side is an expression denoting the new value (simply the number
  509. two in this case).
  510.  
  511.      x := 2
  512.  
  513. The following, more complex example uses the value stored in the variable
  514. before the assignment as part of the expression for the new data.  The
  515. value of the expression on the right-hand side of the := is the value
  516. stored in the variable x plus one.  This value is then stored in x,
  517. over-writing the previous data.  (So, the overall effect is that x is
  518. incremented.)
  519.  
  520.      x := x + 1
  521.  
  522. This may be clearer in the next example which does not change the data
  523. stored in x.  In fact, this piece of code is just a waste of CPU time,
  524. since all it does is look up the value stored in x and store it back there!
  525.  
  526.      x := x
  527.  
  528. ========================================================================
  529.  
  530.  
  531. Global and local variables (and procedure parameters)
  532. -----------------------------------------------------
  533.  
  534.    There are two kinds of variable: global and local.  Data stored by
  535. global variables can be read and changed by all procedures, but data
  536. stored by local variables can only be accessed by the procedure to which
  537. they are local.  Global variables must be declared before the first
  538. procedure definition.  Local variables are declared within the procedure
  539. to which they are local (i.e., between the PROC and ENDPROC).  For
  540. example, the following code declares a global variable w and local
  541. variables x and y.
  542.  
  543.      DEF w
  544.      
  545.      PROC main()
  546.        DEF x
  547.        x:=2
  548.        w:=1
  549.        fred()
  550.      ENDPROC
  551.      
  552.      PROC fred()
  553.        DEF y
  554.        y:=3
  555.        w:=2
  556.      ENDPROC
  557.  
  558. The variable x is local to the procedure main, and y is local to fred.
  559. The procedures main and fred can read and alter the value of the global
  560. variable w, but fred cannot read or alter the value of x (since that
  561. variable is local to main).  Similarly, main cannot read or alter y.
  562.  
  563.    The local variables of one procedure are, therefore, completely
  564. different to the local variables of another procedure.  For this reason
  565. they can share the same names without confusion.  So, in the above
  566. example, the local variable y in fred could have been called x and the
  567. program would have done exactly the same thing.
  568.  
  569.      DEF w
  570.      
  571.      PROC main()
  572.        DEF x
  573.        x:=2
  574.        w:=1
  575.        fred()
  576.      ENDPROC
  577.      
  578.      PROC fred()
  579.        DEF x
  580.        x:=3
  581.        w:=2
  582.      ENDPROC
  583.  
  584. This works because the x in the assignment in fred can refer only to the
  585. local variable x of fred (the x in main is local to main so cannot be
  586. accessed from fred).
  587.  
  588.    If a local variable for a procedure has the same name as a global
  589. variable then in the rest of the procedure the name refers only to the
  590. local variable.  Therefore, the global variable cannot be accessed in the
  591. procedure, and this is called descoping the global variable.
  592.  
  593.    The parameters of a procedure are local variables for that procedure.
  594. We've seen how to pass values as parameters when a procedure is called
  595. (the use of WriteF in the example), but until now we haven't been able to
  596. define a procedure which takes parameters.  Now we know a bit about
  597. variables we can have a go:
  598.  
  599.      DEF y
  600.      
  601.      PROC onemore(x)
  602.        y:=x+1
  603.      ENDPROC
  604.  
  605. This isn't a complete program so don't try to compile it.  Basically,
  606. we've declared a variable y (which will be of type LONG) and a procedure
  607. onemore.  The procedure is defined with a parameter x, and this is just
  608. like a (local) variable declaration.  When onemore is called a parameter
  609. must be supplied, and this value is stored in the (local) variable x
  610. before execution of onemore's code.  The code stores the value of x plus
  611. one in the (global) variable y.  The following are some examples of
  612. calling onemore:
  613.  
  614.        onemore(120)
  615.        onemore(52+34)
  616.        onemore(y)
  617.  
  618.    A procedure can be defined to take any number of parameters.  Below,
  619. the procedure addthem is defined to take two parameters, a and b, so it
  620. must therefore be called with two parameters.  Notice that values stored
  621. by the parameter variables (a and b) can be changed within the code of the
  622. procedure.
  623.  
  624.      DEF y
  625.      
  626.      PROC addthem(a, b)
  627.        a:=a+2
  628.        y:=a*b
  629.      ENDPROC
  630.  
  631. The following are some examples of calling addthem:
  632.  
  633.        addthem(120,-20)
  634.        addthem(52,34)
  635.        addthem(y,y)
  636.  
  637. ========================================================================
  638.  
  639.  
  640. Changing the example
  641. --------------------
  642.  
  643.    Before we change the example we must learn something about WriteF.  We
  644. already know that the characters \n in a string mean a linefeed.  However,
  645. there are several other important combinations of characters in a string,
  646. and some are special to procedures like WriteF.  One such combination is
  647. \d, which is easier to describe after we've seen the changed example.
  648.  
  649.      PROC main()
  650.        WriteF('My first program\n')
  651.        fred()
  652.      ENDPROC
  653.      
  654.      PROC fred()
  655.        WriteF('...brought to you by the number \d\n', 236)
  656.      ENDPROC
  657.  
  658. You might be able to guess what happens, but compile it and try it out
  659. anyway.  If everything's worked you should see that the second message
  660. prints out the number that was passed as the second parameter to WriteF.
  661. That's what the \d combination does--it marks the place in the string
  662. where the number should be printed.  Here's the output the example should
  663. generate:
  664.  
  665.      My first program
  666.      ...brought to you by the number 236
  667.  
  668. Try this next change:
  669.  
  670.      PROC main()
  671.        WriteF('My first program\n')
  672.        fred()
  673.      ENDPROC
  674.      
  675.      PROC fred()
  676.        WriteF('...the number \d is quite nice\n', 16)
  677.      ENDPROC
  678.  
  679. This is very similar, and just shows that the \d really does mark the
  680. place where the number is printed.  Again, here's the output it should
  681. generate:
  682.  
  683.      My first program
  684.      ...the number 16 is quite nice
  685.  
  686. We'll now try printing two numbers.
  687.  
  688.      PROC main()
  689.        WriteF('My first program\n')
  690.        fred()
  691.      ENDPROC
  692.      
  693.      PROC fred()
  694.        WriteF('...brought to you by the numbers \d and \d\n', 16, 236)
  695.      ENDPROC
  696.  
  697. Because we're printing two numbers we need two lots of \d, and we need to
  698. supply two numbers as parameters in the order in which we want them to be
  699. printed.  The number 16 will therefore be printed before the word `and'
  700. and before the number 236.  Here's the output:
  701.  
  702.      My first program
  703.      ...brought to you by the numbers 16 and 236
  704.  
  705.    We can now make a big step forward and pass the numbers as parameters
  706. to the procedure fred.  Just look at the differences between this next
  707. example and the previous one.
  708.  
  709.      PROC main()
  710.        WriteF('My first program\n')
  711.        fred(16, 236)
  712.      ENDPROC
  713.      
  714.      PROC fred(a,b)
  715.        WriteF('...brought to you by the numbers \d and \d\n', a,b)
  716.      ENDPROC
  717.  
  718. This time we pass the (local) variables a and b to WriteF.  This is
  719. exactly the same as passing the values they store (which is what the
  720. previous example did), and so the output will be the same.  In the next
  721. section we'll manipulate the variables by doing some arithmetic with a and
  722. b, and get WriteF to print the results.
  723.  
  724. ========================================================================
  725.  
  726.  
  727. Expressions
  728. ===========
  729.  
  730.    The E language includes the normal mathematical and logical operators.
  731. These operators are combined with values (usually in variables) to give
  732. expressions which yield new values.  The following sections discuss this
  733. topic in more detail.
  734.  
  735. Next:
  736.  
  737.   Mathematics  
  738.   Logic and comparison  
  739.   Precedence and grouping  
  740.  
  741. ========================================================================
  742.  
  743.  
  744. Mathematics
  745. -----------
  746.  
  747.    All the standard mathematical operators are supported in E. You can do
  748. addition, subtraction, multiplication and division.  Other functions such
  749. as sine, modulus and square-root can also be used as they are part of the
  750. Amiga system libraries, but we only need to know about simple mathematics
  751. at the moment.  The + character is used for addition, - for subtraction, *
  752. for multiplication (it's the closest you can get to a multiplication sign
  753. on a keyboard without using the letter x), and / for division (be careful
  754. not to confuse the \  used in strings with / used for division).  The
  755. following are examples of expressions:
  756.  
  757.        1+2+3+4
  758.        15-5
  759.        5*2
  760.        330/33
  761.        -10+20
  762.        3*3+1
  763.  
  764. Each of these expressions yields ten as its result.  The last example is
  765. very carefully written to get the precedence correct (see
  766. Precedence and grouping).
  767.  
  768. ========================================================================
  769.  
  770.  
  771. Logic and comparison
  772. --------------------
  773.  
  774.    Logic lies at the very heart of a computer.  They rarely guess what to
  775. do next; instead they rely on hard facts and precise reasoning.  Consider
  776. the password protection on most games.  The computer must decide whether
  777. you entered the correct number or word before it lets you play the game.
  778. When you play the game it's constantly making decisions: did your laser
  779. hit the alien, have you got any lives left, etc.  Logic controls the
  780. operation of a program.
  781.  
  782.    In E, the constants TRUE and FALSE represent the truth values true and
  783. false (respectively), and the operators AND and OR are the standard logic
  784. operators.  The comparison operators are = (equal to), > (greater than), <
  785. (less than), >= (greater than or equal to), <= (less than or equal to) and
  786. <> (not equal to).  All the following expressions are true:
  787.  
  788.        TRUE
  789.        TRUE AND TRUE
  790.        TRUE OR FALSE
  791.        1=1
  792.        2>1
  793.        3<>0
  794.  
  795. And these are all false:
  796.  
  797.        FALSE
  798.        TRUE AND FALSE
  799.        FALSE OR FALSE
  800.        0=2
  801.        2<1
  802.        (2<1) AND (-1=0)
  803.  
  804. The last example must use parentheses.  We'll see why in the next section
  805. (it's to do with precedence, again).
  806.  
  807.    The truth values TRUE and FALSE are actually numbers.  This is how the
  808. logic system works in E. TRUE is the number -1 and FALSE is zero.  The
  809. logic operators AND and OR expect such numbers as their parameters.  In
  810. fact, the AND and OR operators are really bit-wise operators (see
  811. Bitwise AND and OR), so most of the time any non-zero number is taken to
  812. be TRUE.  It can sometimes be convenient to rely on this knowledge,
  813. although most of the time it is preferable (and more readable) to use a
  814. slightly more explicit form.  Also, these facts can cause a few subtle
  815. problems as we shall see in the next section.
  816.  
  817. ========================================================================
  818.  
  819.  
  820. Precedence and grouping
  821. -----------------------
  822.  
  823.    At school most of us are taught that multiplications must be done
  824. before additions in a sum.  In E it's different--there is no operator
  825. precedence.  This means that expressions like 1+3*3 do not give the
  826. results a mathematician might expect.  In fact, 1+3*3 represents the
  827. number 12 in E. This is because the addition, 1+3, is done before the
  828. multiplication, since it occurs before the multiplication.  If the
  829. multiplication were written before the addition it would be done first
  830. (like we would normally expect).  Therefore, 3*3+1 represents the number
  831. 10 in E and in school mathematics.
  832.  
  833.    To overcome this difference we can use parentheses to group the
  834. expression.  If we'd written 1+(3*3) the result would be 10.  This is
  835. because we've forced E to do the multiplication first.  Although this may
  836. seem troublesome to begin with, it's actually a lot better than learning a
  837. lot of rules for deciding which operator is done first (in C this can be a
  838. real pain, and you usually end up writing the brackets in just to be
  839. sure!).
  840.  
  841.    The logic examples above contained the expression:
  842.  
  843.        (2<1) AND (-1=0)
  844.  
  845. This expression was false.  If we'd left the parentheses out, E would have
  846. seen it as:
  847.  
  848.        ((2<1) AND -1) = 0
  849.  
  850. Now the number -1 shouldn't really be used to represent a truth value with
  851. AND, but we do know that TRUE is the number -1, so E will make sense of
  852. this and the E compiler won't complain.  We will soon see how AND and OR
  853. really work (see Bitwise AND and OR), but for now we'll just work out what
  854. E would calculate for this expression:
  855.  
  856.   1. Two is not less than one so 2<1 can be replaced by FALSE.
  857.  
  858.             (FALSE AND -1) = 0
  859.  
  860.   2.     TRUE is -1 so we can replace -1 by TRUE.
  861.  
  862.             (FALSE AND TRUE) = 0
  863.  
  864.   3.     FALSE AND TRUE is FALSE.
  865.  
  866.             (FALSE) = 0
  867.  
  868.   4.     FALSE is really the number zero, so we can replace it with zero.
  869.  
  870.             0 = 0
  871.  
  872.   5. Zero is equal to zero, so the expression is TRUE.
  873.  
  874.             TRUE
  875.  
  876. So E calculates the expression to be true.  But the original expression
  877. (with parentheses) was false.  Bracketing is therefore very important!  It
  878. is also very easy to do correctly.
  879.  
  880. ========================================================================
  881.  
  882.  
  883. Program Flow Control
  884. ********************
  885.  
  886.    A computer program often needs to repeatedly execute a series of
  887. statements or execute different statements according to the result of some
  888. decision.  For example, a program to print all the numbers between one and
  889. a thousand would be very long and tedious to write if each print statement
  890. had to be given individually--it would be much better to use a variable
  891. and repeatedly print its value and increment it.  Also, things sometimes
  892. go wrong and a program must decide whether to continue or print an error
  893. message and stop--this part of a program is a typical example of a
  894. conditional block.
  895.  
  896. Next:
  897.  
  898.   Conditional Block  
  899.   Loops  
  900.  
  901. ========================================================================
  902.  
  903.  
  904. Conditional Block
  905. =================
  906.  
  907.    There are two kinds of conditional block: IF and SELECT.  Examples of
  908. these blocks are given below as fragments of E code (i.e., the examples
  909. are not complete E programs).
  910.  
  911.        IF x>0
  912.          x:=x+1
  913.          WriteF('Increment: x is now \d\n', x)
  914.        ELSEIF x<0
  915.          x:=x-1
  916.          WriteF('Decrement: x is now \d\n', x)
  917.        ELSE
  918.          WriteF('Zero: x is 0\n')
  919.        ENDIF
  920.  
  921. In the above IF block, the first part checks if the value of x is greater
  922. than zero, and, if it is, x is incremented and the new value is printed
  923. (with a message saying it was incremented).  The program will then skip
  924. the rest of the block, and will execute the statements which follow the
  925. ENDIF.  If, however, x it is not greater than zero the ELSEIF part is
  926. checked, so if x is less than zero it will be decremented and printed, and
  927. the rest of the block is skipped.  If x is not greater than zero and not
  928. less than zero the statements in the ELSE part are executed, so a message
  929. saying x is zero is printed.  The IF conditional is described in more
  930. detail below.
  931.  
  932.  
  933.   IF block  
  934.   IF expression  
  935.  
  936.        SELECT x
  937.          CASE 0
  938.            WriteF('x is zero\n')
  939.          CASE 10
  940.            WriteF('x is ten\n')
  941.          CASE -2
  942.            WriteF('x is -2\n')
  943.          DEFAULT
  944.            WriteF('x is not zero, ten or -2\n')
  945.        ENDSELECT
  946.  
  947. The SELECT block is similar to the IF block--it does different things
  948. depending on the value of x.  However, x is only checked against specific
  949. values, given in the series of CASE statements.  If it is not any of these
  950. values the DEFAULT part is executed.  The SELECT block is described in
  951. more detail below.
  952.  
  953. Next:
  954.  
  955.   SELECT block  
  956.  
  957. ========================================================================
  958.  
  959.  
  960. IF block
  961. --------
  962.  
  963.    The IF block has the following form (the bits like expression are
  964. descriptions of the kinds of E code which is allowed at that point--they
  965. are not proper E code):
  966.  
  967.        IF expressionA
  968.          statementsA
  969.        ELSEIF expressionB
  970.          statementsB
  971.        ELSE
  972.          statementsC
  973.        ENDIF
  974.  
  975. This block means:
  976.  
  977.    * If expressionA is true (i.e., represents TRUE or any non-zero number)
  978.      the code denoted by statementsA is executed.
  979.  
  980.    * If expressionA is false (i.e., represents FALSE or zero) and
  981.      expressionB is true the statementsB part is executed.
  982.  
  983.    * If both expressionA and expressionB are false the statementsC part is
  984.      executed.
  985.  
  986. There does not need to be an ELSE part but if one is present it must be
  987. the last part (immediately before the ENDIF).  Also, there can be any
  988. number of ELSEIF parts between the IF and ELSE parts.
  989.  
  990.    An alternative to this vertical form (where each part is on a separate
  991. line) is the horizontal form:
  992.  
  993.        IF expression THEN statementA ELSE statementB
  994.  
  995. This has the disadvantage of no ELSEIF parts and having to cram everything
  996. onto a single line.  Notice the presence of the THEN keyword to separate
  997. the expression and statement.  This horizontal form is closely related to
  998. the IF expression, which is described below (see IF expression).
  999.  
  1000.    To help make things clearer here are a number of E code fragments which
  1001. illustrate the allowable IF blocks:
  1002.  
  1003.        IF x>0 THEN x:=x+1 ELSE x:=0
  1004.      
  1005.        IF x>0
  1006.          x:=x+1
  1007.        ELSE
  1008.          x:=0
  1009.        ENDIF
  1010.      
  1011.        IF x=0 THEN WriteF('x is zero\n')
  1012.      
  1013.        IF x=0
  1014.          WriteF('x is zero\n')
  1015.        ENDIF
  1016.      
  1017.        IF x<0
  1018.          Write('Negative x\n')
  1019.        ELSIF x>2000
  1020.          Write('Too big x\n')
  1021.        ELSIF (x=2000) OR (x=0)
  1022.          Write('Worrying x\n')
  1023.        ENDIF
  1024.      
  1025.        IF x>0
  1026.          IF x>2000
  1027.            WriteF('Big x\n')
  1028.          ELSE
  1029.            WriteF('OK x\n')
  1030.          ENDIF
  1031.        ELSE
  1032.          IF x<-800 THEN WriteF('Small x\n') ELSE Write('Negative OK x')
  1033.        ENDIF
  1034.  
  1035. In the last example there are nested IF blocks (i.e., an IF block within
  1036. an IF block).  There is no ambiguity in which ELSE or ELSEIF parts belong
  1037. to which IF block because the beginning and end of the IF blocks are
  1038. clearly marked.  For instance, the first ELSE line can only be interpreted
  1039. as being part of the innermost IF block.
  1040.  
  1041.    As a matter of style the conditions on the IF and ELSEIF parts should
  1042. not overlap (i.e., at most one of the conditions should be true).  If they
  1043. do, however, the first one will take precedence.  Therefore, the following
  1044. two fragments of E code do the same thing:
  1045.  
  1046.        IF x>0
  1047.          WriteF('x is bigger than zero\n')
  1048.        ELSEIF x>200
  1049.          WriteF('x is bigger than 200\n')
  1050.        ELSE
  1051.          WriteF('x is too small\n')
  1052.        ENDIF
  1053.      
  1054.        IF x>0
  1055.          WriteF('x is bigger than zero\n')
  1056.        ELSE
  1057.          WriteF('x is too small\n')
  1058.        ENDIF
  1059.  
  1060. The ELSEIF part of the first fragment checks whether x is greater than 200.
  1061. But, if it is, the check in the IF part would have been true (x is
  1062. certainly greater than zero if it's greater than 200), and so only the
  1063. code in the IF part is executed.  The whole IF block behaves as if the
  1064. ELSEIF was not there.
  1065.  
  1066. ========================================================================
  1067.  
  1068.  
  1069. IF expression
  1070. -------------
  1071.  
  1072.    IF is such a commonly used construction that there is also an IF
  1073. expression.  The IF block is a statement and it controls which lines of
  1074. code are executed, whereas the IF expression is an expression and it
  1075. controls its own value.  For example, the following IF block:
  1076.  
  1077.        IF x>0
  1078.          y:=x+1
  1079.        ELSE
  1080.          y:=0
  1081.        ENDIF
  1082.  
  1083. can be written more succinctly using an IF expression:
  1084.  
  1085.        y:=(IF x>0 THEN x+1 ELSE 0)
  1086.  
  1087. The parentheses are unnecessary but they help to make the example more
  1088. readable.  Since the IF block is just choosing between two assignments to
  1089. y it isn't really the lines of code that are different (they are both
  1090. assignments), rather it is the values that are assigned to y that are
  1091. different.  The IF expression makes this similarity very clear.  It
  1092. chooses the value to be assigned in just the same way that the IF block
  1093. choose the assignment.
  1094.  
  1095.    As you can see, IF expressions are written like the horizontal form of
  1096. the IF block.  However, there must be an ELSE part and there can be no
  1097. ELSEIF parts.  This means that the expression will always have a value,
  1098. and it isn't cluttered with lots of cases.
  1099.  
  1100.    Don't worry too much about IF expressions, since there are only useful
  1101. in a handful of cases and can always be rewritten as a more wordy IF block.
  1102. Having said that they are very elegant and a lot more readable than the
  1103. equivalent IF block.
  1104.  
  1105. ========================================================================
  1106.  
  1107.  
  1108. SELECT block
  1109. ------------
  1110.  
  1111.    The SELECT block has the following form:
  1112.  
  1113.        SELECT variable
  1114.        CASE expressionA
  1115.          statementsA
  1116.        CASE expressionB
  1117.          statementsB
  1118.        DEFAULT
  1119.          statementsC
  1120.        ENDSELECT
  1121.  
  1122. The value of the selection variable (denoted by variable in the SELECT
  1123. part) is compared with the result of the expressions in each of the CASE
  1124. parts in turn.  If there's a match, the statements in the (first) matching
  1125. CASE part are executed.  There can be any number of CASE parts between the
  1126. SELECT and DEFAULT parts.  If there are no matches, the statements in the
  1127. DEFAULT part are executed.  There does not need to be an DEFAULT part but
  1128. if one is present it must be the last part (immediately before the
  1129. ENDSELECT).
  1130.  
  1131.    It should be clear that SELECT blocks can be rewritten as IF blocks,
  1132. with the checks on the IF and ELSEIF parts being equality checks.  For
  1133. example, the following code fragments are equivalent:
  1134.  
  1135.        SELECT x
  1136.        CASE 22
  1137.          WriteF('x is 22\n')
  1138.        CASE (y+z)/2
  1139.          WriteF('x is (y+x)/2\n')
  1140.        DEFAULT
  1141.          WriteF('x isn't anything significant\n')
  1142.        ENDSELECT
  1143.      
  1144.        IF x=22
  1145.          WriteF('x is 22\n')
  1146.        ELSEIF x=(y+z)/2
  1147.          WriteF('x is (y+x)/2\n')
  1148.        ELSE
  1149.          WriteF('x isn't anything significant\n')
  1150.        ENDIF
  1151.  
  1152. Notice that the IF and ELSEIF parts come from the CASE parts, the ELSE
  1153. part comes from the DEFAULT part, and the order of the parts is preserved.
  1154. The advantage of the SELECT block is that it's much easier to see that the
  1155. value of x is being tested all the time, and also we don't have to keep
  1156. writing x= in the checks.
  1157.  
  1158. ========================================================================
  1159.  
  1160.  
  1161. Loops
  1162. =====
  1163.  
  1164.    Loops are all about making a program execute a series of statements
  1165. over and over again.  Probably the simplest loop to understand is the FOR
  1166. loop.  There are other kinds of loops, but they are easier to understand
  1167. once we know how to use a FOR loop.
  1168.  
  1169. Next:
  1170.  
  1171.   FOR loop  
  1172.   WHILE loop  
  1173.   REPEAT..UNTIL loop  
  1174.  
  1175. ========================================================================
  1176.  
  1177.  
  1178. FOR loop
  1179. --------
  1180.  
  1181.    If you want to write a program to print the numbers one to 100 you can
  1182. either type each number and wear out your fingers, or you can use a single
  1183. variable and a small FOR loop.  Try compiling this E program (the space
  1184. after the \d is needed to separate the printed numbers):
  1185.  
  1186.      PROC main()
  1187.        DEF x
  1188.        FOR x:=1 TO 100
  1189.          WriteF('\d ', x)
  1190.        ENDFOR
  1191.        WriteF('\n')
  1192.      ENDPROC
  1193.  
  1194. When you run this you'll get all the numbers from one to 100 printed, just
  1195. like we wanted.  It works by using the (local) variable x to hold the
  1196. number to be printed.  The FOR loop starts off by setting the value of x
  1197. to one (the bit that looks like an assignment).  Then the statements
  1198. between the FOR and ENDFOR lines are executed (so the value of x gets
  1199. printed).  When the program reaches the ENDFOR it increments x and checks
  1200. to see if it is bigger than 100 (the limit we set with the TO part).  If
  1201. it is, the loop is finished and the statements after the ENDFOR are
  1202. executed.  If, however, it wasn't bigger than 100, the statements between
  1203. the FOR and ENDFOR lines are executed all over again, and this time x is
  1204. one bigger since it has been incremented.  In fact, this program does
  1205. exactly the same as the following program (the ... is not E code--it
  1206. stands for the 97 other WriteF statements):
  1207.  
  1208.      PROC main()
  1209.        WriteF('\d ', 1)
  1210.        WriteF('\d ', 2)
  1211.        ...
  1212.        WriteF('\d ', 100)
  1213.        WriteF('\n')
  1214.      ENDPROC
  1215.  
  1216.    The general form of the FOR loop is as follows:
  1217.  
  1218.        FOR var := expressionA TO expressionB STEP number
  1219.          statements
  1220.        ENDFOR
  1221.  
  1222. The var bit stands for the loop variable (in the example above this was x).
  1223. The expressionA bit gives the start value for the loop variable and the
  1224. expressionB bit gives the last allowable value for it.  The STEP part
  1225. allows you to specify the value (given by number) which is added to the
  1226. loop variable on each loop.  Unlike the values given for the start and end
  1227. (which can be arbitrary expressions), the STEP value must be an explicit
  1228. number, i.e., a constant (see Constants).  The STEP value defaults to one
  1229. if the STEP part is omitted (as in our example).  Negative STEP values are
  1230. allowed, but in this case the check used at the end of each loop is
  1231. whether the loop variable is less than the value in the TO part.  Zero is
  1232. not allowed as the STEP value.
  1233.  
  1234.    As with the IF block there is a horizontal form of a FOR loop:
  1235.  
  1236.        FOR var := expA TO expB STEP expC DO statement
  1237.  
  1238. ========================================================================
  1239.  
  1240.  
  1241. WHILE loop
  1242. ----------
  1243.  
  1244.    The FOR loop used a loop variable and checked whether that variable had
  1245. gone past its limit.  A WHILE loop allows you to specify your own loop
  1246. check.  For instance, this program does the same as the program in the
  1247. previous section:
  1248.  
  1249.      PROC main()
  1250.        DEF x
  1251.        x:=1
  1252.        WHILE x<=100
  1253.          WriteF('\d ', x)
  1254.          x:=x+1
  1255.        ENDWHILE
  1256.        WriteF('\n')
  1257.      ENDPROC
  1258.  
  1259. We've replaced the FOR loop with initialisation of x and a WHILE loop with
  1260. an extra statement to increment x.  We can now see the inner workings of
  1261. the FOR loop and, in fact, this is exactly how the FOR loop works.
  1262.  
  1263.    It is important to know that our check, x<=100, is done before the loop
  1264. statements are executed.  This means that the loop statements might not
  1265. even be executed once.  For instance, if we'd made the check x>=100 it
  1266. would be false at the beginning of the loop (since x is initialised to one
  1267. in the assignment before the loop).  Therefore, the loop would have
  1268. terminated immediately and execution would pass straight to the statements
  1269. after the ENDWHILE.
  1270.  
  1271.    Here's a more complicated example:
  1272.  
  1273.      PROC main()
  1274.        DEF x,y
  1275.        x:=1
  1276.        y:=2
  1277.        WHILE (x<10) AND (y<10)
  1278.          WriteF('x is \d and y is \d\n', x, y)
  1279.          x:=x+2
  1280.          y:=y+2
  1281.        ENDWHILE
  1282.      ENDPROC
  1283.  
  1284. We've used two (local) variables this time.  As soon as one of them is ten
  1285. or more the loop is terminated.  A bit of inspection of the code reveals
  1286. that x is initialised to one, and keeps having two added to it.  It will,
  1287. therefore, always be an odd number.  Similarly, y will always be even.
  1288. The WHILE check shows that it won't print any numbers which are greater
  1289. than or equal to ten.  From this and the fact that x starts at one and y
  1290. at two we can decide that the last pair of numbers will be seven and eight.
  1291. Run the program to confirm this.  It should produce the following output:
  1292.  
  1293.      x is 1 and y is 2
  1294.      x is 3 and y is 4
  1295.      x is 5 and y is 6
  1296.      x is 7 and y is 8
  1297.  
  1298.    Like the FOR loop, there is a horizontal form of the WHILE loop:
  1299.  
  1300.        WHILE expression DO statement
  1301.  
  1302.    Loop termination is always a big problem.  FOR loops are guaranteed to
  1303. eventually reach their limit (if you don't mess with the loop variable,
  1304. that is).  However, WHILE loops (and all other loops) may go on forever
  1305. and never terminate.  For example, if the loop check were 1<2 it would
  1306. always be true and nothing the loop could do would prevent it being true!
  1307. You must therefore take care that you make sure your loops terminate in
  1308. some way if you want to program to finish.  There is a sneaky way of
  1309. terminating loops using the JUMP statement, but we'll ignore that for now.
  1310.  
  1311. ========================================================================
  1312.  
  1313.  
  1314. REPEAT..UNTIL loop
  1315. ------------------
  1316.  
  1317.    A REPEAT..UNTIL loop is very similar to a WHILE loop.  The only
  1318. difference is where you specify the loop check, and when and how the check
  1319. is performed.  To illustrate this, here's the program from the previous
  1320. two sections rewritten using a REPEAT..UNTIL loop (try to spot the subtle
  1321. differences):
  1322.  
  1323.      PROC main()
  1324.        DEF x
  1325.        x:=1
  1326.        REPEAT
  1327.          WriteF('\d ', x)
  1328.          x:=x+1
  1329.        UNTIL x>100
  1330.        WriteF('\n')
  1331.      ENDPROC
  1332.  
  1333. Just as in the WHILE loop version we've got an initialisation of x and an
  1334. extra statement in the loop to increment x.  However, this time the loop
  1335. check is specified at the end of the loop (in the UNTIL part), and the
  1336. check is only performed at the end of each loop.  This difference means
  1337. that the code in a REPEAT..UNTIL loop will be executed at least once,
  1338. whereas the code in a WHILE loop may never be executed.  Also, the logical
  1339. sense of the check follows the English: a REPEAT..UNTIL loop executes
  1340. until the check is true, whereas the WHILE loop executes while the
  1341. check is true.  Therefore, the REPEAT..UNTIL loop executes while the check
  1342. is false!  This may seem confusing at first, but just remember to read the
  1343. code as if it were English and you'll get the correct interpretation.
  1344.  
  1345. ========================================================================
  1346.  
  1347.  
  1348. Summary
  1349. *******
  1350.  
  1351.    This is the end of Part One, which was hopefully enough to get you
  1352. started.  If you've grasped the main concepts you are good position to
  1353. attack Part Two, which covers the E language in more detail.
  1354.  
  1355.    This is probably a good time to look at the different parts of one of
  1356. the examples from the previous sections, since we've now used quite a bit
  1357. of E. The following examination uses the WHILE loop example.  Just to make
  1358. things easier to follow, each line has been numbered (don't try to compile
  1359. it with the line numbers on!).
  1360.  
  1361.       1.  PROC main()
  1362.       2.    DEF x,y
  1363.       3.    x:=1
  1364.       4.    y:=2
  1365.       5.    WHILE (x<10) AND (y<10)
  1366.       6.      WriteF('x is \d and y is \d\n', x, y)
  1367.       7.      x:=x+2
  1368.       8.      y:=y+2
  1369.       9.    ENDWHILE
  1370.      10.  ENDPROC
  1371.  
  1372. Hopefully, you should be able to recognise all the features listed in the
  1373. table below.  If you don't then you might need to go back over the
  1374. previous chapters, or find a much better programming guide than this!
  1375.  
  1376.      Line(s)  Observation
  1377.      ---------------------------------------------------------
  1378.       1-10    The procedure definition.
  1379.      
  1380.          1    The declaration of the procedure main, with no
  1381.               parameters.
  1382.      
  1383.          2    The declaration of local variables x and y.
  1384.      
  1385.       3, 4    Initialisation of x and y using assignment
  1386.               statements.
  1387.      
  1388.        5-9    The WHILE loop.
  1389.      
  1390.          5    The loop check for the WHILE loop using the
  1391.               logical operator AND, the comparison operator
  1392.               <, and parentheses to group the expression.
  1393.      
  1394.          6    The call to the (built-in) procedure WriteF
  1395.               using parameters.  Notice the string, the place
  1396.               holders for numbers, \d, and the linefeed,
  1397.               \n.
  1398.      
  1399.       7, 8    Assignments to x and y, adding two to
  1400.               their values.
  1401.      
  1402.          9    The marker for the end of the WHILE loop.
  1403.      
  1404.         10    The marker for the end of the procedure.
  1405.  
  1406. ========================================================================
  1407.  
  1408.  
  1409. Format and Layout
  1410. *****************
  1411.  
  1412.    In this chapter we'll look at the rules which govern the format and
  1413. layout of E code.  In the previous Part we saw examples of E code that
  1414. were quite nicely indented and the structure of the program was easily
  1415. visible.  This was just a convention and the E language does not constrain
  1416. you to write code in this way.  However, there are certain rules that must
  1417. be followed.  (This chapter refers to some concepts and parts of the E
  1418. language which were not covered in Part One.  Don't let this put you
  1419. off--those things will be dealt with in later chapters, and it's maybe a
  1420. good idea to read this chapter again when they have been.)
  1421.  
  1422. Next:
  1423.  
  1424.   Identifiers  
  1425.   Statements  
  1426.   Spacing and Separators  
  1427.   Comments  
  1428.  
  1429. ========================================================================
  1430.  
  1431.  
  1432. Identifiers
  1433. ===========
  1434.  
  1435.    An identifier is a word which the compiler must interpret rather than
  1436. treating literally.  For instance, a variable is an identifier, as is a
  1437. keyword (e.g., IF), but anything in a string is not (e.g., fred in 'fred
  1438. and wilma' is not an identifier).  Identifiers can be made up of upper- or
  1439. lower-case letters, numbers and underscores (the _ character).  There are
  1440. only two constraints:
  1441.  
  1442.   1. The first character cannot be a number (this would cause confusion
  1443.      with numeric constants).
  1444.  
  1445.   2. The case of the first few characters of identifiers is significant.
  1446.  
  1447. For keywords (e.g., ENDPROC), constants (e.g., TRUE) and assembly
  1448. mnemonics (e.g., MOVE.L) the first two characters must both be uppercase.
  1449. For E built-in or Amiga system procedures/functions the first character
  1450. must be uppercase and the second must be lowercase.  For all other
  1451. identifiers (i.e., local, global and procedure parameter variables, object
  1452. names and element names, procedure names and code labels) the first
  1453. character must be lowercase.
  1454.  
  1455.    Apart from these constraints you are free to write identifiers how you
  1456. like, although it's arguably more tasteful to use all lowercase for
  1457. variables and all uppercase for keywords and constants.
  1458.  
  1459. ========================================================================
  1460.  
  1461.  
  1462. Statements
  1463. ==========
  1464.  
  1465.    A statement is normally a single line of an instruction to the computer.
  1466. Each statement normally occupies a single line.  If a procedure is thought
  1467. of as a paragraph then a statement is a sentence.  Variables, expressions
  1468. and keywords are the words which make up the sentence.
  1469.  
  1470.    So far in our examples we have met only two kinds of statement: the
  1471. single line statement and the multi-line statement.  The assignments we
  1472. have seen were single line statements, and the vertical form of the IF
  1473. block is a multi-line statement.  The horizontal form of the IF block was
  1474. actually the single line statement form of the IF block.  Notice that
  1475. statements can be built up from other statements, as is the case for IF
  1476. blocks.  The code parts between the IF, ELSEIF, ELSE and ENDIF lines are
  1477. sequences of statements.
  1478.  
  1479.    Single line statements can often be very short, and you may be able to
  1480. fit several of them onto an single line without the line getting too long.
  1481. To do this in E you use a semi-colon (the ; character) to separate each
  1482. statement on the line.  For example, the following code fragments are
  1483. equivalent:
  1484.  
  1485.        fred(y,z)
  1486.        y:=x
  1487.        x:=z+1
  1488.      
  1489.        fred(y,z); y:=x; x:=z+1
  1490.  
  1491.    On the other hand you may want to split a long statement over several
  1492. lines.  This is a bit more tricky because the compiler needs to see that
  1493. you haven't finished the statement when it gets to the end of a line.
  1494. Therefore you can only break a statement in certain places.  The most
  1495. common place is after a comma that is part of the statement (like in a
  1496. procedure call with more than one paramter), but you can also split a line
  1497. after most binary operators.  The following examples are rather silly but
  1498. show some allowable line breaking places.
  1499.  
  1500.         fred(a, b, c,
  1501.              d, e, f)
  1502.         x:=x+
  1503.            y+
  1504.            z
  1505.  
  1506. The complete list of binary operators after which you can split the line
  1507. is:
  1508.  
  1509.      +    -    *    /
  1510.      =    >    <    <>   >=   <=
  1511.      AND  OR   BUT
  1512.  
  1513.    Strings may also get a bit long.  You can split them over several lines
  1514. by breaking them into several separate strings and using + between them.
  1515. If a line ends with a + and the previous thing on the line was a string
  1516. then the E compiler takes the next string to be a continuation.  The
  1517. following calls to WriteF print the same thing:
  1518.  
  1519.        WriteF('This long string can be broken over several lines.\n')
  1520.      
  1521.        WriteF('This long string ' +
  1522.               'can be broken over several lines.\n')
  1523.      
  1524.        WriteF('This long' +
  1525.               ' string can be ' +
  1526.               'broken over several ' +
  1527.               'lines.\n')
  1528.  
  1529. ========================================================================
  1530.  
  1531.  
  1532. Spacing and Separators
  1533. ======================
  1534.  
  1535.    The examples we've seen so far used a rigid indentation convention
  1536. which was intended to illuminate the structure of the program.  This was
  1537. just a convention, and the E language places no constraints on the amount
  1538. of whitespace (spaces, tabs and linefeeds) you place between statements.
  1539. However, within statements you must supply enough spacing to make the
  1540. statement readable.  This generally means that you must put whitespace
  1541. between adjacent identifiers which start or end with a letter, number or
  1542. underscore (so that the compiler does not think it's one big identifier!).
  1543. In practice this means you should put a space after a keyword if it might
  1544. run into a variable or procedure name.  Most other times (like in
  1545. expressions) identifiers are separated by non-identifier characters (a
  1546. comma, parenthesis or other symbol).
  1547.  
  1548. ========================================================================
  1549.  
  1550.  
  1551. Comments
  1552. ========
  1553.  
  1554.    A comment is something that the E compiler ignores and is only there to
  1555. help the reader.  Remember that one day in the future you may be the
  1556. reader, and it may be quite hard to decipher your own code without a few
  1557. decent comments!  Comments are therefore pretty important.
  1558.  
  1559.    You can write comments anywhere you can write whitespace that isn't
  1560. part of a string.  The start of a comment is marked by /* and the end by
  1561. */, so you must be careful not to write /* or */ as part of the
  1562. comment text, unless these delimit a nested comment.  In practice a
  1563. comment is best put on a line by itself or after the end of the code on a
  1564. line.
  1565.  
  1566.         /* This line is a comment */
  1567.         x:=1  /* This line contains an assignment then a comment */
  1568.      /* y:=2  /* This whole line is a comment with a nested comment */*/
  1569.  
  1570. ========================================================================
  1571.  
  1572.  
  1573. Functions
  1574. *********
  1575.  
  1576.    A function is a procedure which returns a value.  This value can be any
  1577. expression so it may depend on the parameters with which the function was
  1578. called.  For instance, the addition operator + can be thought of as a
  1579. function which returns the sum of its two parameters.
  1580.  
  1581. Next:
  1582.  
  1583.   Procedures as Functions  
  1584.   One-Line Functions  
  1585.  
  1586. ========================================================================
  1587.  
  1588.  
  1589. Procedures as Functions
  1590. =======================
  1591.  
  1592.    We can define our own addition function, add, in a very similar way to
  1593. the definition of a procedure.  (The only difference is that a function
  1594. explicitly returns a value.)
  1595.  
  1596.      PROC main()
  1597.        DEF sum
  1598.        sum:=12+79
  1599.        WriteF('Using +, sum is \d\n', sum)
  1600.        sum:=add(12,79)
  1601.        WriteF('Using add, sum is \d\n', sum)
  1602.      ENDPROC
  1603.      
  1604.      PROC add(x, y)
  1605.        DEF s
  1606.        s:=x+y
  1607.      ENDPROC s
  1608.  
  1609. This should generate the following output:
  1610.  
  1611.      Using +, sum is 91
  1612.      Using add, sum is 91
  1613.  
  1614. In the procedure add the value s is returned using the ENDPROC label.  The
  1615. value returned from add can be used in expressions, just like any other
  1616. value.  You do this by writing the procedure call where you want the value
  1617. to be.  In the above example we wanted the value to be assigned to sum so
  1618. we wrote the call to add on the right-hand side of the assignment.  Notice
  1619. the similarities between the uses of + and add.  In general, add(a,b) can
  1620. be used in exactly the same places that a+b can (more precisely, it can be
  1621. used anywhere (a+b) can be used).
  1622.  
  1623.    The RETURN keyword can also be used to return values from a procedure.
  1624. If the ENDPROC method is used then the value is returned when the
  1625. procedure reaches the end of its code.  However, if the RETURN method is
  1626. used the value is returned immediately at that point and no more of the
  1627. procedure's code is executed.  Here's the same example using RETURN:
  1628.  
  1629.      PROC add(x, y)
  1630.        DEF s
  1631.        s:=x+y
  1632.        RETURN s
  1633.      ENDPROC
  1634.  
  1635. The only difference is that you can write RETURN anywhere in the code part
  1636. of a procedure and it finishes the execution of the procedure at that
  1637. point (rather than execution finishing when it reaches the end of the
  1638. code).  In fact, you can use RETURN in the main procedure to prematurely
  1639. finish the execution of a program.
  1640.  
  1641.    Here's a slightly more complicated use of RETURN:
  1642.  
  1643.      PROC limitedadd(x,y)
  1644.        IF x>10000
  1645.          RETURN 10000
  1646.        ELSEIF x<-10000
  1647.          RETURN -10000
  1648.        ELSE
  1649.          RETURN x+y
  1650.        ENDIF
  1651.        x:=1
  1652.        IF x=1 THEN RETURN 9999 ELSE RETURN -9999
  1653.      ENDPROC
  1654.  
  1655. This function checks to see if x is greater than 10,000 or less than
  1656. -10,000, and if it is a limited value is returned (which is generally not
  1657. the correct sum!).  If x is between -10,000 and 10,000 the correct answer
  1658. is returned.  The lines after the first IF block will never get executed
  1659. because execution will have finished at one of the RETURN lines.  Those
  1660. lines are therefore just a waste of compiler time and can safely be
  1661. omitted.
  1662.  
  1663.    If no value is given with the ENDPROC or RETURN keyword then zero is
  1664. returned.  Therefore, all procedures are actually functions (and the terms
  1665. procedure and function will tend to be used interchangeably).  So, what
  1666. happens to the value when you write a procedure call on a line by itself,
  1667. not in an expression?  Well, as we will see, the value is simply discarded
  1668. (see Turning an Expression into a Statement).  This is what happened in
  1669. the previous examples when we called the procedures fred and WriteF.
  1670.  
  1671. ========================================================================
  1672.  
  1673.  
  1674. One-Line Functions
  1675. ==================
  1676.  
  1677.    Just as the IF block and FOR loop have horizontal, single line forms,
  1678. so does a procedure definition.  The general form is:
  1679.  
  1680.      PROC name (arg1arg2, ...) RETURN expression
  1681.  
  1682. At first sight this might seem pretty unusable, but it is useful for very
  1683. simple functions and our add function in the previous section is a good
  1684. example.  If you look closely at the original definition you'll see that
  1685. the local variable s wasn't really needed.  Here's the one-line definition
  1686. of add:
  1687.  
  1688.      PROC add(x,y) RETURN x+y
  1689.  
  1690. ========================================================================
  1691.  
  1692.  
  1693. Constants
  1694. *********
  1695.  
  1696.    A constant is a value that does not change.  A number like 121 is a
  1697. good example of a constant--its value is always 121.  We've already met
  1698. another kind of constant: string constants (see Strings).  As you can
  1699. doubtless tell, constants are pretty important things.
  1700.  
  1701. Next:
  1702.  
  1703.   Numeric Constants  
  1704.   String Constants Special Character Sequences  
  1705.   Named Constants  
  1706.   Enumerations  
  1707.   Sets  
  1708.  
  1709. ========================================================================
  1710.  
  1711.  
  1712. Numeric Constants
  1713. =================
  1714.  
  1715.    We've met a lot of numbers in the previous examples.  Technically
  1716. speaking, these were numeric constants (constant because they don't change
  1717. value like a variable might).  They were all decimal numbers, but you can
  1718. use hexadecimal and binary numbers as well.  There's also a way of
  1719. specifying a number using characters.  To specify a hexadecimal number you
  1720. use a $ before the digits (and after the optional minus sign - to
  1721. represent a negative value).  To specify a binary number you use a %
  1722. instead.
  1723.  
  1724.    Specifying numbers using characters is more complicated, because the
  1725. base of this system is 256 (the base of decimal is ten, that of
  1726. hexadecimal is 16 and that of binary is two).  The digits are enclosed in
  1727. double-quotes (the " character), and there can be at most four digits.
  1728. Each digit is a character representing its ASCII value.  Therefore, the
  1729. character A represents 65 and the character 0 (zero) represents 48.  This
  1730. upshot of this is that character A has ASCII value "A" in E, and "0z"
  1731. represents ("0" * 256) + "z" = (48 * 256) + 122 = 12,410.  However, you
  1732. probably don't need to worry about anything other than the single
  1733. character case, which gives you the ASCII value of the character.
  1734.  
  1735.    The following table shows the decimal value of several numeric
  1736. constants.  Notice that you can use upper- or lower-case letters for the
  1737. hexadecimal constants.  Obviously the case of characters is significant
  1738. for character numbers.
  1739.  
  1740.       Number  Decimal value
  1741.      ----------------------
  1742.          21          21
  1743.        -143        -143
  1744.         $1a          26
  1745.        -$B1        -177
  1746.       %1110          14
  1747.      -%1010         -10
  1748.         "z"         122
  1749.        "Je"      19,045
  1750.        -"A"         -65
  1751.  
  1752. ========================================================================
  1753.  
  1754.  
  1755. String Constants: Special Character Sequences
  1756. =============================================
  1757.  
  1758.    We have seen that in a string the character sequence \n means a
  1759. linefeed (see Strings).  There are several other similar such special
  1760. character sequences which represent useful characters that can't be typed
  1761. in a string.  The following table shows all these sequences.  Note that
  1762. there are some other similar sequences which are used to control
  1763. formatting with built-in procedures like WriteF.  These are listed where
  1764. WriteF and similar procedures are described (see
  1765. Input and output functions).
  1766.  
  1767.      Sequence          Meaning
  1768.      --------------------------------------
  1769.         \0     A null (ASCII zero)
  1770.         \a     An apostrophe '
  1771.         \b     A carriage return (ASCII 13)
  1772.         \e     An escape (ASCII 27)
  1773.         \n     A linefeed (ASCII 10)
  1774.         \t     A tab (ASCII 9)
  1775.         \\     A backslash \
  1776.  
  1777. ========================================================================
  1778.  
  1779.  
  1780. Named Constants
  1781. ===============
  1782.  
  1783.    It is often nice to be able to give names to certain constants.  For
  1784. instance, as we saw earlier, the truth value TRUE actually represents the
  1785. value -1, and FALSE represents zero (see Logic and comparison).  These are
  1786. our first examples of named constants.  To define your own you use the
  1787. CONST keyword as follows:
  1788.  
  1789.      CONST ONE=1, LINEFEED=10, BIG_NUM=999999
  1790.  
  1791. This has defined the constant ONE to represent one, LINEFEED ten and
  1792. BIG_NUM 999,999.  Named constants must begin with two uppercase letters,
  1793. as mentioned before (see Identifiers).
  1794.  
  1795.    You can use previously defined constants to give the value of a new
  1796. constant, but in this case the definitions must occur on different CONST
  1797. lines.
  1798.  
  1799.      CONST ZERO=0
  1800.      CONST ONE=ZERO+1
  1801.      CONST TWO=ONE+1
  1802.  
  1803. The expression used to define the value of a constant can use only simple
  1804. operators (no function calls) and constants.
  1805.  
  1806. ========================================================================
  1807.  
  1808.  
  1809. Enumerations
  1810. ============
  1811.  
  1812.    Often you want to define a whole lot of constants and you just want
  1813. them all to have a different value so you can tell them apart easily.  For
  1814. instance, if you wanted to define some constants to represent some famous
  1815. cities and you only needed to know how to distinguish one from another
  1816. then you could use an enumeration like this:
  1817.  
  1818.      ENUM LONDON, MOSCOW, NEW_YORK, PARIS, ROME, TOKYO
  1819.  
  1820. The ENUM keyword begins the definitions (like the CONST keyword does for
  1821. an ordinary constant definition).  The actual values of the constants
  1822. start at zero and stretch up to five.  In fact, this is exactly the same
  1823. as writing:
  1824.  
  1825.      CONST LONDON=0, MOSCOW=1, NEW_YORK=2, PARIS=3, ROME=4, TOKYO=5
  1826.  
  1827.    The enumeration does not have to start at zero, though.  You can change
  1828. the starting value at any point by specifying a value for an enumerated
  1829. constant.  For example, the following constant definitions are equivalent:
  1830.  
  1831.      ENUM APPLE, ORANGE, CAT=55, DOG, GOLDFISH, FRED=-2,
  1832.           BARNEY, WILMA, BETTY
  1833.      
  1834.      CONST APPLE=0, ORANGE=1, CAT=55, DOG=56, GOLDFISH=57,
  1835.            FRED=-2, BARNEY=-1, WILMA=0, BETTY=1
  1836.  
  1837. ========================================================================
  1838.  
  1839.  
  1840. Sets
  1841. ====
  1842.  
  1843.    Yet another kind of constant definition is the set definition.  This
  1844. useful for defining flag sets, i.e., a number of options each of which can
  1845. be on or off.  The definition is like a simple enumeration, but using the
  1846. SET keyword and this time the values start at one and increase as powers
  1847. of two (so the next value is two, the next is four, the next eight, and so
  1848. on).  Therefore, the following definitions are equivalent:
  1849.  
  1850.      SET ENGLISH, FRENCH, GERMAN, JAPANESE, RUSSIAN
  1851.      
  1852.      CONST ENGLISH=1, FRENCH=2, GERMAN=4, JAPANESE=8, RUSSIAN=16
  1853.  
  1854. However, the significance of the values it is best shown by using binary
  1855. constants:
  1856.  
  1857.      CONST ENGLISH=%00001, FRENCH=%00010, GERMAN=%00100,
  1858.            JAPANESE=%01000, RUSSIAN=%10000
  1859.  
  1860. If a person speaks just English then we can use the constant ENGLISH.  If
  1861. they also spoke Japanese then to represent this with a single value we'd
  1862. normally need a new constant (something like ENG_JAP).  In fact, we'd
  1863. probably need a constant for each combination of languages a person might
  1864. know.  However, with the set definition we can OR the ENGLISH and JAPANESE
  1865. values together to get a new value, %01001, and this represents a set
  1866. containing both ENGLISH and JAPANESE.  On the other hand, to find out if
  1867. someone speaks French we would AND the value for the languages they know
  1868. with %00010 (or the constant FRENCH).  (As you might have guessed, AND and
  1869. OR are really bit-wise operators, not simply logical operators.  See
  1870. Bitwise AND and OR.)
  1871.  
  1872.    Consider this program fragment:
  1873.  
  1874.        speak:=GERMAN OR ENGLISH OR RUSSIAN  /* Speak any of these */
  1875.        IF speak AND JAPANESE
  1876.          /* Can speak Japanese */
  1877.          WriteF('Can speak Japenese\n')
  1878.        ELSE
  1879.          /* Can't speak Japanese */
  1880.          WriteF('Can\at speak Japenese\n')
  1881.        ENDIF
  1882.        IF speak AND (GERMAN OR FRENCH)
  1883.          /* Can speak German or French */
  1884.          WriteF('Can speak both German and French\n')
  1885.        ELSE
  1886.          /* Can't speak German or French */
  1887.          WriteF('Can\at speak neither German nor French\n')
  1888.        ENDIF
  1889.  
  1890. The assignment sets speak to show that the person can speak German,
  1891. English or Russian.  The first IF block tests whether the person can speak
  1892. Japanese, and the second tests whether they can speak German or French.
  1893.  
  1894.    When using sets be careful you don't get tempted to add values instead
  1895. of OR-ing them.  Adding two different constants from the same set is the
  1896. same as OR-ing them, but adding a constant to itself isn't.  This is not
  1897. the only time addition doesn't give the same answer, but it's the most
  1898. obvious.  If you to stick to using OR you won't have a problem.
  1899.  
  1900. ========================================================================
  1901.  
  1902.  
  1903. Types
  1904. *****
  1905.  
  1906.    We've already met the LONG type and found that this was the normal type
  1907. for variables (see Variable types).  The types INT and LIST were also
  1908. mentioned.  Learning how to use types in an effective and readable way is
  1909. very important.  The type of a variable (as well as its name) can give
  1910. clues to the reader about how or for what it is used.  There are also more
  1911. fundamental reasons for needing types, e.g., to logically group data using
  1912. objects (see OBJECT Type).
  1913.  
  1914.    This is a very large chapter and you might like to take it slowly.  One
  1915. of the most important things to get to grips with is pointers.
  1916. Concentrate on trying to understand these as they play a large part in any
  1917. kind of system programming.
  1918.  
  1919. Next:
  1920.  
  1921.   LONG Type  
  1922.   PTR Type  
  1923.   ARRAY Type  
  1924.   OBJECT Type  
  1925.   LIST and STRING Types  
  1926.   Linked Lists  
  1927.  
  1928. ========================================================================
  1929.  
  1930.  
  1931. LONG Type
  1932. =========
  1933.  
  1934.    The LONG type is the most important type because it is the default type
  1935. and by far the most common type.  It can be used to store a variety of
  1936. data, including memory addresses, as we shall see.
  1937.  
  1938. Next:
  1939.  
  1940.   Default type  
  1941.   Memory addresses  
  1942.  
  1943. ========================================================================
  1944.  
  1945.  
  1946. Default type
  1947. ------------
  1948.  
  1949.    LONG is the default type of variables.  It is a 32-bit type, meaning
  1950. that 32-bits of memory (RAM) are used to store the data for each variable
  1951. of this type and the data can take (integer) values in the range
  1952. -2,147,483,648 to 2,147,483,647.  Variables can explicitly be declared as
  1953. LONG:
  1954.  
  1955.      DEF x:LONG, y
  1956.      
  1957.      PROC fred(p:LONG, q, r:LONG)
  1958.        DEF zed:LONG
  1959.        statements
  1960.      ENDPROC
  1961.  
  1962. The global variable x, procedure parameters p and r, and local variable
  1963. zed have all been declared to be LONG values.  The declarations are
  1964. very similar to the kinds we've seen before, except that the variables
  1965. have :LONG after their name in the declaration.  This is the way the type
  1966. of a variable is given.  Note that the global variable y and the procedure
  1967. parameter q are also LONG, since they do not have a type specified and
  1968. LONG is the default type for variables.
  1969.  
  1970. ========================================================================
  1971.  
  1972.  
  1973. Memory addresses
  1974. ----------------
  1975.  
  1976.    There's a very good reason why LONG is the normal type.  A 32-bit
  1977. (integer) value can be used as a memory address.  Therefore we can store
  1978. the address (or location) of data in a variable (the variable is then
  1979. called a pointer).  The variable would then not contain the value of the
  1980. data but a way of finding the data.  Once the data location is known the
  1981. data can be read or even altered!  The next section covers pointers and
  1982. addresses in more detail.  (see PTR Type.)
  1983.  
  1984. ========================================================================
  1985.  
  1986.  
  1987. PTR Type
  1988. ========
  1989.  
  1990.    The PTR type is used to hold memory addresses.  Variables which have a
  1991. PTR type are called pointers (since they store memory addresses, as
  1992. mentioned in the previous section).  This section describes, in detail,
  1993. addresses, pointers and the PTR type.
  1994.  
  1995. Next:
  1996.  
  1997.   Addresses  
  1998.   Pointers  
  1999.   Indirect types  
  2000.   Finding addresses (making pointers)  
  2001.   Extracting data (dereferencing pointers)  
  2002.   Procedure parameters  
  2003.  
  2004. ========================================================================
  2005.  
  2006.  
  2007. Addresses
  2008. ---------
  2009.  
  2010.    To understand memory addresses, a good analogy is to think of memory as
  2011. a road or street, each memory location as a post-box on a house, and each
  2012. piece of data as a letter.  If you were a postman you would need to know
  2013. where to put your letters, and this information is given by the address of
  2014. the post-box.  As time goes by, each post-box is filled with different
  2015. letters.  This is like the value in a memory location (or variable)
  2016. changing.  To change the letters stored in your post-box, you tell your
  2017. friends your address and they can send letters in and fill it.  This is
  2018. like letting some program change your data by giving it the address of the
  2019. data.
  2020.  
  2021.    The next two diagrams illustrate this analogy.  A letter contains an
  2022. address which points to a particular house (or lot of mail) on a street.
  2023.  
  2024.             +-------+
  2025.             | Letter|
  2026.             |-------|
  2027.             |Address+----*
  2028.             +-------+     \
  2029.                            \
  2030.                             \
  2031.               +--------+ +---\----+ +--------+     +--------+
  2032.               | House  | | House  | | House  |     | House  |
  2033.      Street:  |+------+| |+------+| |+------+| ... |+------+|
  2034.               || Mail || || Mail || || Mail ||     || Mail ||
  2035.               +========+ +========+ +========+     +========+
  2036.  
  2037. A pointer contains an address which points to a variable (or data) in
  2038. memory.
  2039.  
  2040.             +-------+
  2041.             |Pointer|
  2042.             |-------|
  2043.             |Address+----*
  2044.             +-------+     \
  2045.                            \
  2046.                             \
  2047.               +--------+ +---\----+ +--------+     +--------+
  2048.               |Variable| |Variable| |Variable|     |Variable|
  2049.      Memory:  |+------+| |+------+| |+------+| ... |+------+|
  2050.               || Data || || Data || || Data ||     || Data ||
  2051.               +========+ +========+ +========+     +========+
  2052.  
  2053. ========================================================================
  2054.  
  2055.  
  2056. Pointers
  2057. --------
  2058.  
  2059.    Variables which contain memory addresses are called pointers.  As we
  2060. saw in the previous section, we can store memory addresses in LONG
  2061. variables.  However, we then don't know the type of the data stored at
  2062. those addresses.  If it is important (or useful) to know this then the PTR
  2063. type (or, more accurately, one of the many PTR types) should be used.
  2064.  
  2065.      DEF p:PTR TO LONG, i:PTR TO INT,
  2066.          cptr:PTR TO CHAR, gptr:PTR TO gadget
  2067.  
  2068. The values stored in each of p, cptr, i and gptr are LONG since they are
  2069. memory addresses.  However, the data at the address stored in p is taken
  2070. to be LONG (a 32-bit value), that at cptr is CHAR (an 8-bit value), that
  2071. at i is INT (a 16-bit value), and that at gptr is gadget, which is an
  2072. object (see OBJECT Type).
  2073.  
  2074. ========================================================================
  2075.  
  2076.  
  2077. Indirect types
  2078. --------------
  2079.  
  2080.    In the previous example we saw INT and CHAR used as the destination
  2081. types of pointers, and these are the 16- and 8-bit equivalents
  2082. (respectively) of the LONG type.  However, unlike LONG these types cannot
  2083. be used directly to declare global or local variables, or procedure
  2084. parameters.  They can only be used in constructing types (for instance
  2085. with PTR TO).  The following declarations are therefore illegal, and it
  2086. might be nice to try compiling a little program with such a declaration,
  2087. just to see the error message the E compiler gives.
  2088.  
  2089.      /* This program fragment contains illegal declarations */
  2090.      DEF c:CHAR, i:INT
  2091.      
  2092.      /* This program fragment contains illegal declarations */
  2093.      PROC fred(a:INT, b:CHAR)
  2094.        DEF x:INT
  2095.        statements
  2096.      ENDPROC
  2097.  
  2098.    This is not much of a limitation because you can store INT or CHAR
  2099. values in LONG variables if you really need to.  However, it does mean
  2100. there's a nice, simple rule: every direct value in E is a 32-bit quantity,
  2101. either a LONG or a pointer.  In fact, LONG is actually short-hand for PTR
  2102. TO CHAR, so you can use LONG values like they were actually PTR TO CHAR
  2103. values.
  2104.  
  2105. ========================================================================
  2106.  
  2107.  
  2108. Finding addresses (making pointers)
  2109. -----------------------------------
  2110.  
  2111.    If a program knows the address of a variable it can directly read or
  2112. alter the value stored in the variable.  To obtain the address of a simple
  2113. variable you use { and } around the variable name.  The address of
  2114. non-simple variables (e.g., objects and arrays) can be found much more
  2115. easily (see the appropriate section), and in fact you will very rarely
  2116. need to use {var }.  However, if you understand how to explicitly make
  2117. pointers with {var } and use the pointers to get to data, then you'll
  2118. understand the way pointers are used for the non-simple types much more
  2119. quickly.
  2120.  
  2121.    Addresses can be stored in a variable, passed to a procedure or
  2122. whatever (they're just 32-bit values).  Try out the following program:
  2123.  
  2124.      DEF x
  2125.      
  2126.      PROC main()
  2127.        fred(2)
  2128.      ENDPROC
  2129.      
  2130.      PROC fred(y)
  2131.        DEF z
  2132.        WriteF('x is at address \d\n', {x})
  2133.        WriteF('y is at address \d\n', {y})
  2134.        WriteF('z is at address \d\n', {z})
  2135.        WriteF('fred is at address \d\n', {fred})
  2136.      ENDPROC
  2137.  
  2138. Notice that you can also find the address of a procedure using { and }.
  2139. This is is the memory location of the code the procedure represents.
  2140. Here's the output from one execution of this program:
  2141.  
  2142.      x is at address 3758280
  2143.      y is at address 3758264
  2144.      z is at address 3758252
  2145.      fred is at address 3732878
  2146.  
  2147. This is an interesting program to run several times under different
  2148. circumstances.  You should see that sometimes the numbers for the
  2149. addresses change.  Running the program when another is multi-tasking (and
  2150. eating memory) should produce the best changes, whereas running it
  2151. consecutively (in one CLI) should produce the smallest (if any) changes.
  2152. This gives you a glimpse at the complex memory handling of the Amiga and
  2153. the E compiler.
  2154.  
  2155. ========================================================================
  2156.  
  2157.  
  2158. Extracting data (dereferencing pointers)
  2159. ----------------------------------------
  2160.  
  2161.    If you have an address stored in a variable (i.e., a pointer) you can
  2162. extract the data using the ^ operator.  This act of extracting data via a
  2163. pointer is called dereferencing the pointer.  This operator should only
  2164. really be used when {var } has been used to obtain an address.  To this
  2165. end, LONG values are read and written when dereferencing pointers in this
  2166. way.  For pointers to non-simple types (e.g., objects and arrays),
  2167. dereferencing is achieved in much more readable ways (see the appropriate
  2168. section for details), and this operator is not used.  In fact,  ^var is
  2169. seldom used in programs, but is useful for explaining how pointers work,
  2170. especially in conjunction with {var }.
  2171.  
  2172.    Using pointers can remove the scope restriction on local variables,
  2173. i.e., they can be altered from outside the procedure for which they are
  2174. local.  Whilst this kind of use is not generally advised, it makes for a
  2175. good example which shows the power of pointers.  For example, the
  2176. following program changes the value of the local variable x for the
  2177. procedure fred from within the procedure barney.
  2178.  
  2179.      PROC main()
  2180.        fred()
  2181.      ENDPROC
  2182.      
  2183.      PROC fred()
  2184.        DEF x, p:PTR TO LONG
  2185.        x:=33
  2186.        p:={x}
  2187.        barney(p)
  2188.        WriteF('x is now \d\n', x)
  2189.      ENDPROC
  2190.      
  2191.      PROC barney(ptr:PTR TO LONG)
  2192.        DEF val
  2193.        val:=^ptr
  2194.        ^ptr:=val-6
  2195.      ENDPROC
  2196.  
  2197. Here's what you can expect it to generate as output:
  2198.  
  2199.      x is now 27
  2200.  
  2201. Notice that the ^ operator (i.e., dereferencing) is quite versatile.  In
  2202. the first assignment of the procedure barney it is used (with the pointer
  2203. ptr) to get the value stored in the local variable x, and in the second it
  2204. is used to change this variable's value.  In either case, dereferencing
  2205. makes the pointer behave exactly as if you'd written the variable for
  2206. which it is a pointer.  To emphasise this, we can remove the barney
  2207. procedure, like we did above (see Style Reuse and Readability):
  2208.  
  2209.      PROC main()
  2210.        fred()
  2211.      ENDPROC
  2212.      
  2213.      PROC fred()
  2214.        DEF x, p:PTR TO LONG, val
  2215.        x:=33
  2216.        p:={x}
  2217.        val:=x
  2218.        x:=val-6
  2219.        WriteF('x is now \d\n', x)
  2220.      ENDPROC
  2221.  
  2222. Everywhere the barney procedure used ^ptr we've written x (because we are
  2223. now in the procedure for which x is local).  We've also eliminated the ptr
  2224. variable (the parameter to the barney procedure), since it was only used
  2225. with the ^ operator.
  2226.  
  2227.    To make things clear the fred and barney example is deliberately
  2228. `wordy'.  The val and p variables are unnecessary, and the pointer types
  2229. could be abbreviated to LONG or even omitted, for the reasons outlined
  2230. above (see LONG Type).  This is the compact form of the example:
  2231.  
  2232.      PROC main()
  2233.        fred()
  2234.      ENDPROC
  2235.      
  2236.      PROC fred()
  2237.        DEF x
  2238.        x:=33
  2239.        barney({x})
  2240.        WriteF('x is now \d\n', x)
  2241.      ENDPROC
  2242.      
  2243.      PROC barney(ptr)
  2244.        ^ptr:=^ptr-6
  2245.      ENDPROC
  2246.  
  2247.    By far the most common use of pointers is to address (or reference)
  2248. large structures of data.  It would be extremely expensive (in terms of
  2249. CPU time) to pass large amounts of data from procedure to procedure, so
  2250. addresses to such data are passed instead (and, as we know, these are just
  2251. 32-bit values).  The Amiga system functions (such as ones for creating
  2252. windows) require a lot of structured data, so if you plan to do any real
  2253. programming you are going to have to understand and use pointers.
  2254.  
  2255. ========================================================================
  2256.  
  2257.  
  2258. Procedure parameters
  2259. --------------------
  2260.  
  2261.    Only local and global variables have the luxury of a large choice of
  2262. types.  Procedure parameters can only be LONG or PTR TO type.  This is not
  2263. really a big limitation as we shall see in the later sections.
  2264.  
  2265. ========================================================================
  2266.  
  2267.  
  2268. ARRAY Type
  2269. ==========
  2270.  
  2271.    Quite often, the data used by a program needs to be ordered in some
  2272. way, primarily so that it can be accessed easily.  E provides a way to
  2273. achieve such simple ordering: the ARRAY type.  This type (in its various
  2274. forms) is common to most computer languages.
  2275.  
  2276. Next:
  2277.  
  2278.   Tables of data  
  2279.   Accessing array data  
  2280.   Array pointers  
  2281.   Point to other elements  
  2282.   Array procedure parameters  
  2283.  
  2284. ========================================================================
  2285.  
  2286.  
  2287. Tables of data
  2288. --------------
  2289.  
  2290.    Data can be grouped together in many different ways, but probably the
  2291. most common and straight-forward way is to make a table.  In a table the
  2292. data is ordered either vertically or horizontally, but the important thing
  2293. is the relative positioning of the elements.  The E view of this kind of
  2294. ordered data is the ARRAY type.  An array is just a fixed sized collection
  2295. of data in order.  The size of an array is important and this is fixed
  2296. when it is declared.  The following illustrates array declarations:
  2297.  
  2298.      DEF a[132]:ARRAY,
  2299.          table[21]:ARRAY OF LONG,
  2300.          ints[3]:ARRAY OF INT,
  2301.          objs[54]:ARRAY OF myobject
  2302.  
  2303. The size of the array is given in the square brackets ([ and ]).  The type
  2304. of the elements in the array defaults to CHAR, but this can be given
  2305. explicitly using the OF keyword and the type name.  However, only LONG,
  2306. INT, CHAR and object types are allowed (LONG can hold pointer values
  2307. so this isn't much of a limitation).  Object types are described below
  2308. (see OBJECT Type).
  2309.  
  2310.    As mentioned above, procedure parameters cannot be arrays (see
  2311. Procedure parameters).  We will overcome this limitation soon (see
  2312. Array procedure parameters).
  2313.  
  2314. ========================================================================
  2315.  
  2316.  
  2317. Accessing array data
  2318. --------------------
  2319.  
  2320.    To access a particular element in an array you use square brackets
  2321. again, this time specifying the index (or position) of the element you
  2322. want.  Indices start at zero for the first element of the array, one for
  2323. the second element and, in general, (n-1) for the n-th element.  This may
  2324. seem strange at first, but it's the way most computer languages do it!  We
  2325. will see a reason why this makes sense soon (see Array pointers).
  2326.  
  2327.      DEF a[10]:ARRAY
  2328.      
  2329.      PROC main()
  2330.        DEF i
  2331.        FOR i:=0 TO 9
  2332.          a[i]:=i*i
  2333.        ENDFOR
  2334.        WriteF('The 7th element of the array a is \d\n', a[6])
  2335.        a[a[2]]:=10
  2336.        WriteF('The array is now:\n')
  2337.        FOR i:=0 TO 9
  2338.          WriteF(' a[\d] = \d\n', i, a[i])
  2339.        ENDFOR
  2340.      ENDPROC
  2341.  
  2342. This should all seem very straight-forward although one of the lines looks
  2343. a bit complicated.  Try to work out what happens to the array after the
  2344. assignment immediately following the first WriteF.  In this assignment the
  2345. index comes from a value stored in the array itself!  Be careful when
  2346. doing complicated things like this, though: make sure you don't try to
  2347. read data from or write data to elements beyond the end of the array.  In
  2348. our example there are only ten elements in the array a, so it wouldn't be
  2349. sensible to talk about the eleventh element.  The program could have
  2350. checked that the value stored at a[2] was a number between zero and nine
  2351. before trying to access that array element, but it wasn't necessary in
  2352. this case.  Here's the output this example should generate:
  2353.  
  2354.      The 7th element of the array a is 36
  2355.      The array is now:
  2356.       a[0] = 0
  2357.       a[1] = 1
  2358.       a[2] = 4
  2359.       a[3] = 9
  2360.       a[4] = 10
  2361.       a[5] = 25
  2362.       a[6] = 36
  2363.       a[7] = 49
  2364.       a[8] = 64
  2365.       a[9] = 81
  2366.  
  2367.    If you do try to write to a non-existent array element strange things
  2368. can happen.  This may be practically unnoticeable (like corrupting some
  2369. other data), but if you're really unlucky you might crash your computer.
  2370. The moral is: stay within the bounds of the array.
  2371.  
  2372.    A short-hand for the first element of an array (i.e., the one with an
  2373. index of zero) is to omit the index and write only the square brackets.
  2374. Therefore, a[] is the same as a[0].
  2375.  
  2376. ========================================================================
  2377.  
  2378.  
  2379. Array pointers
  2380. --------------
  2381.  
  2382.    When you declare an array the address of the (beginning of the) array
  2383. is given by the variable name without square brackets.  Consider the
  2384. following program:
  2385.  
  2386.      DEF a[10]:ARRAY OF INT
  2387.      
  2388.      PROC main()
  2389.        DEF ptr:PTR TO INT, i
  2390.        FOR i:=0 TO 9
  2391.          a[i]:=i
  2392.        ENDFOR
  2393.        ptr:=a
  2394.        ptr++
  2395.        ptr[]:=22
  2396.        FOR i:=0 TO 9
  2397.          WriteF('a[\d] is \d\n', i, a[i])
  2398.        ENDFOR
  2399.      ENDPROC
  2400.  
  2401. Here's the output from it:
  2402.  
  2403.      a[0] is 0
  2404.      a[1] is 22
  2405.      a[2] is 2
  2406.      a[3] is 3
  2407.      a[4] is 4
  2408.      a[5] is 5
  2409.      a[6] is 6
  2410.      a[7] is 7
  2411.      a[8] is 8
  2412.      a[9] is 9
  2413.  
  2414. You should notice that the second element of the array has been changed
  2415. using the pointer.  The ptr++ statement increments the pointer ptr to
  2416. point to the next element of the array.  It is important that ptr is
  2417. declared as PTR TO INT since the array is an ARRAY OF INT.  The [] is used
  2418. to dereference the pointer and therefore 22 is stored in the second
  2419. element of the array.  In fact, the ptr can be used in exactly the same
  2420. way as an array, so ptr[1] would be the next (or third element) of the
  2421. array a (after the ptr++ statement).  Also, since ptr points to the second
  2422. element of a, negative values may legitimately be used as the index, and
  2423. ptr[-1] is the first element of a.
  2424.  
  2425.    In fact, the following declarations are identical except the first
  2426. reserves an appropriate amount of memory for the array whereas the second
  2427. relies on you having done this somewhere else in the program.
  2428.  
  2429.        DEF a[20]:ARRAY OF INT
  2430.      
  2431.        DEF a:PTR TO INT
  2432.  
  2433.    The following diagram is similar to the diagrams given earlier (see
  2434. Addresses).  It is an illustration of an array, a, which was declared to
  2435. be an array of twenty INTs.
  2436.  
  2437.          +--------+
  2438.          |Variable|
  2439.          |  'a'   |
  2440.          |--------|
  2441.          | Address+----*
  2442.          +--------+     \
  2443.                          \
  2444.                           \
  2445.               +-------+ +--\----+ +-------+     +-------+ +-------+
  2446.               |Unknown| | a[0]  | | a[1]  |     | a[19] | |Unknown|
  2447.      Memory:  |+-----+| |+-----+| |+-----+| ... |+-----+| |+-----+|
  2448.               || XXX || || INT || || INT ||     || INT || || XXX ||
  2449.               +=======+ +=======+ +=======+     +=======+ +=======+
  2450.  
  2451. As you can see, the variable a is a pointer to the reserved chunk of
  2452. memory which contains the array elements.  Parts of memory that aren't
  2453. between a[0] and a[19] are marked as `Unknown' because they are not part
  2454. of the array.  This memory should therefore not be accessed using the
  2455. array a.
  2456.  
  2457. ========================================================================
  2458.  
  2459.  
  2460. Point to other elements
  2461. -----------------------
  2462.  
  2463.    We saw in the previous section how to increment a pointer so that it
  2464. points to the next element in the array.  Decrementing a pointer p (i.e.,
  2465. making it point to the previous element) is done in a similar way, using
  2466. the p-- statement which works in the same way as the p++ statement.  In
  2467. fact, p++ and p-- are really expressions which denote pointer values.  p++
  2468. denotes the address stored in p before it is incremented, and p-- denotes
  2469. the address after p is decremented.  Therefore,
  2470.  
  2471.        addr:=p
  2472.        p++
  2473.  
  2474. does the same as
  2475.  
  2476.        addr:=p++
  2477.  
  2478. And
  2479.  
  2480.        p--
  2481.        addr:=p
  2482.  
  2483. does the same as
  2484.  
  2485.        addr:=p--
  2486.  
  2487.    The reason why ++ and -- should be used to increment and decrement a
  2488. pointer is that values from different types occupy different numbers of
  2489. memory locations.  In fact, a single memory location is a byte, and this
  2490. is eight bits.  Therefore, CHAR values occupy a single byte, whereas LONG
  2491. values take up four bytes (32 bits).  If p were a pointer to CHAR and it
  2492. was pointing to an array (of CHAR) the p+1 memory location would contain
  2493. the second element of the array (and p+2 the third, etc.).  But if p were
  2494. a pointer to an array of LONG the second element in the array would be at
  2495. p+4 (and the third at p+8).  The locations p, p+1, p+2 and p+3 all make up
  2496. the LONG value at address p.  Having to remember things like this is a
  2497. pain, and it's a lot less readable than using ++ or --.  However, you must
  2498. remember to declare your pointer with the correct type in order for ++ and
  2499. -- to work correctly.
  2500.  
  2501. ========================================================================
  2502.  
  2503.  
  2504. Array procedure parameters
  2505. --------------------------
  2506.  
  2507.    Since we now know how to get the address of an array we can simulate
  2508. passing an array as a procedure parameter by passing the address of the
  2509. array.  For example, the following program uses a procedure to fill in the
  2510. first x elements of an array with their index numbers.
  2511.  
  2512.      DEF a[10]:ARRAY OF INT
  2513.      
  2514.      PROC main()
  2515.        DEF i
  2516.        fillin(a, 10)
  2517.        FOR i:=0 TO 9
  2518.          WriteF('a[\d] is \d\n', i, a[i])
  2519.        ENDFOR
  2520.      ENDPROC
  2521.      
  2522.      PROC fillin(ptr:PTR TO INT, x)
  2523.        DEF i
  2524.        FOR i:=0 TO x-1
  2525.          ptr[]:=i
  2526.          ptr++
  2527.        ENDFOR
  2528.      ENDPROC
  2529.  
  2530. Here's the output it should generate:
  2531.  
  2532.      a[0] is 0
  2533.      a[1] is 1
  2534.      a[2] is 2
  2535.      a[3] is 3
  2536.      a[4] is 4
  2537.      a[5] is 5
  2538.      a[6] is 6
  2539.      a[7] is 7
  2540.      a[8] is 8
  2541.      a[9] is 9
  2542.  
  2543. The array a only has ten elements so we shouldn't fill in any more than
  2544. the first ten elements.  Therefore, in the example, the call to the
  2545. procedure fillin should not have a bigger number than ten as the second
  2546. parameter.  Also, we could treat ptr more like an array (and not use ++),
  2547. but in this case using ++ is slightly better since we are assigning to
  2548. each element in turn.  The alternative definition of fillin (without using
  2549. ++) is:
  2550.  
  2551.      PROC fillin2(ptr:PTR TO INT, x)
  2552.        DEF i
  2553.        FOR i:=0 TO x-1
  2554.          ptr[i]:=i
  2555.        ENDFOR
  2556.      ENDPROC
  2557.  
  2558. Also, yet another version of fillin uses the expression form of ++ and the
  2559. horizontal form of the FOR loop to give a really compact definition.
  2560.  
  2561.      PROC fillin3(ptr:PTR TO INT, x)
  2562.        DEF i
  2563.        FOR i:=0 TO x-1 DO ptr[]++:=i
  2564.      ENDPROC
  2565.  
  2566. ========================================================================
  2567.  
  2568.  
  2569. OBJECT Type
  2570. ===========
  2571.  
  2572.    Objects are the E equivalent of C and Assembly structures, or Pascal
  2573. records.  They are like arrays except the elements are named not numbered,
  2574. and the elements can be of different types.  To find a particular element
  2575. in an object you use a name instead of an index (number).
  2576.  
  2577. Next:
  2578.  
  2579.   Example object  
  2580.   Element selection  
  2581.   Element types  
  2582.   Amiga system objects  
  2583.  
  2584. ========================================================================
  2585.  
  2586.  
  2587. Example object
  2588. --------------
  2589.  
  2590.    We'll dive straight in with this first example, and define an object
  2591. and use it.  Object definitions are global and must be made before any
  2592. procedure definitions.
  2593.  
  2594.      OBJECT
  2595.        rec
  2596.        tag, check
  2597.        table[8]:ARRAY
  2598.        data:LONG
  2599.      ENDOBJECT
  2600.      
  2601.      PROC main()
  2602.        DEF a:rec
  2603.        a.tag:=1
  2604.        a.check:=a
  2605.        a.data:=a.tag+(10000*a.tag)
  2606.      ENDPROC
  2607.  
  2608. This program doesn't visibly do anything so there isn't much point in
  2609. compiling it.  What it does do, however, is show how a typical object is
  2610. defined and elements of an object are selected.
  2611.  
  2612.    The object being defined in the example is rec, and its elements are
  2613. defined just like variable declarations (but without a DEF).  There can be
  2614. as many lines of element definitions as you like between the OBJECT and
  2615. ENDOBJECT lines, and each line can contain any number of elements
  2616. separated by commas.  The elements of the rec object are tag and check
  2617. (which are LONG), table (which is an array of CHAR with eight elements)
  2618. and data (which is also LONG).  Every variable of rec object type will
  2619. have space reserved for each of these elements.  The declaration of the
  2620. (local) variable a therefore reserves enough memory for one rec object.
  2621.  
  2622. ========================================================================
  2623.  
  2624.  
  2625. Element selection
  2626. -----------------
  2627.  
  2628.    To select elements in an object obj you use obj.name, where name is one
  2629. of the element names.  In the example, the tag element of the rec object a
  2630. is selected by writing a.tag.  The other elements are selected in a
  2631. similar way.
  2632.  
  2633.    Just like an array declaration the address of an object obj is stored
  2634. in the variable obj, and any pointer of type PTR TO objectname can be used
  2635. just like an object of type objectname.  Therefore, in the previous
  2636. example a is a PTR TO rec.
  2637.  
  2638. ========================================================================
  2639.  
  2640.  
  2641. Element types
  2642. -------------
  2643.  
  2644.    As the example object shows, the elements of an object can have several
  2645. different types.  However, these types are limited to LONG, INT, CHAR,
  2646. ARRAY or another object type.  You can't have PTR TO or ARRAY OF; if you
  2647. try you'll get an error saying `illegal/inappropriate type' at the point
  2648. where your object is defined.  Again, this isn't much of a limitation
  2649. since, as we know, a LONG can hold a memory address.
  2650.  
  2651.    One thing to remember about ARRAY and object-type elements in an
  2652. object: when you select these elements you get a pointer to the array or
  2653. object.  You can store this value in an appropriate pointer variable and
  2654. then access the array or object elements.  For example, if p is pointer to
  2655. an object from our example object type rec, you can store p.table (a
  2656. pointer to the array) in a PTR TO CHAR variable and then access the array
  2657. using this variable.  The following code defines a new object type based
  2658. on rec and shows how to access the ARRAY and object typed elements.
  2659.  
  2660.      OBJECT rec tag, check table[8]:ARRAY data:LONG ENDOBJECT
  2661.      
  2662.      OBJECT bigrec
  2663.        subrec:rec
  2664.        bigtable[22]:ARRAY
  2665.      ENDOBJECT
  2666.      
  2667.      PROC main()
  2668.        DEF b:bigrec, p:PTR TO rec, s, t
  2669.        p:=b.subrec
  2670.        p.tag:=1
  2671.        p.data:=p.tag+(10000*p.tag)
  2672.        s:=b.bigtable
  2673.        s[0]:="A"
  2674.        t:=p.table
  2675.        t[1]:="y"
  2676.      ENDPROC
  2677.  
  2678. Remember that the variables s and t are LONG (since they are declared with
  2679. no explicit type), and so are therefore PTR TO CHAR.
  2680.  
  2681.    If you have an array of objects you can select an element from the
  2682. array and then an element from that object, all in the same expression.
  2683. In fact, the allowable expressions (relating to objects) are:
  2684.  
  2685.        var . obj_element_name
  2686.        var [ expression ] . obj_element_name
  2687.      
  2688.        var . obj_element_name ++
  2689.        var [ expression ] . obj_element_name ++
  2690.      
  2691.        var . obj_element_name --
  2692.        var [ expression ] . obj_element_name --
  2693.  
  2694. The ++ or -- apply to the pointer var.  Here's an example which uses an
  2695. array of objects:
  2696.  
  2697.      OBJECT rec
  2698.        tag, check
  2699.        table[8]:ARRAY
  2700.        data:LONG
  2701.      ENDOBJECT
  2702.      
  2703.      PROC main()
  2704.        DEF a[10]:ARRAY OF rec, p:PTR TO rec, i
  2705.        p:=a
  2706.        FOR i:=0 TO 9
  2707.          a[i].tag:=i
  2708.          p.check++:=i
  2709.        ENDFOR
  2710.        FOR i:=0 TO 9
  2711.          IF a[i].tag<>a[i].check
  2712.            WriteF('Whoops, a[\d] went wrong...\n', i)
  2713.          ENDIF
  2714.        ENDFOR
  2715.      ENDPROC
  2716.  
  2717. If you think about it for long enough you'll see that a[0].tag is the same
  2718. as a.tag.  That's because a is a pointer to the first element of the
  2719. array, and the elements of the array are objects.  Therefore, a is a
  2720. pointer to an object (the first object in the array).
  2721.  
  2722. ========================================================================
  2723.  
  2724.  
  2725. Amiga system objects
  2726. --------------------
  2727.  
  2728.    There are many different Amiga system objects.  For instance, there's
  2729. one which contains the information needed to make a gadget (like the
  2730. `close' gadget on most windows), and one which contains all the
  2731. information about a process or task.  These objects are vitally important
  2732. and so are supplied with E in the form of `modules'.  Each module is
  2733. specific to a certain area of the Amiga system and contains object and
  2734. other definitions.  Modules are discussed in more detail later (see
  2735. Modules).
  2736.  
  2737. ========================================================================
  2738.  
  2739.  
  2740. LIST and STRING Types
  2741. =====================
  2742.  
  2743.    Arrays are common to many computer languages.  However, they can be a
  2744. bit of a pain because you always need to make sure you haven't run off the
  2745. end of the array when you're writing to it.  This is where the STRING and
  2746. LIST types come in.  STRING is very much like ARRAY OF CHAR and LIST is
  2747. like ARRAY OF LONG.  However, each has a set of E (built-in) functions
  2748. which safely manipulate variables of these types without exceeding their
  2749. bounds.
  2750.  
  2751. Next:
  2752.  
  2753.   Normal strings and E-strings  
  2754.   String functions  
  2755.   Lists and E-lists  
  2756.   List functions  
  2757.   Complex types  
  2758.   Typed lists  
  2759.   Static data  
  2760.  
  2761. ========================================================================
  2762.  
  2763.  
  2764. Normal strings and E-strings
  2765. ----------------------------
  2766.  
  2767.    Normal strings are common to most programming languages.  They are
  2768. simply an array of characters, with the end of the string marked by a null
  2769. character (ASCII zero).  We've already met normal strings (see Strings).
  2770. The ones we used were constant strings contained in ' characters, and they
  2771. denote pointers to the memory where the string data is stored.  Therefore,
  2772. you can assign a string constant to a pointer (to CHAR), and you've got an
  2773. array with ready-filled elements, i.e., an initialised array.
  2774.  
  2775.        DEF s:PTR TO CHAR
  2776.        s:='This is a string constant'
  2777.        /* Now s[] is T and s[2] is i */
  2778.  
  2779. Remember that LONG is actually PTR TO CHAR so this code is precisely the
  2780. same as:
  2781.  
  2782.        DEF s
  2783.        s:='This is a string constant'
  2784.  
  2785. The following diagram illustrates the above assignment to s.  The first
  2786. two characters s[0] and s[1]) are T and h, and the last character (before
  2787. the terminating null, or zero) is t.  Memory marked as `Unknown' is not
  2788. part of the string constant.
  2789.  
  2790.         +--------+
  2791.         |Variable|
  2792.         |  's'   |
  2793.         |--------|
  2794.         |Address +----*
  2795.         +--------+     \
  2796.                         \
  2797.                          \
  2798.              +-------+ +--\----+ +-------+   +-------+ +-------+ +-------+
  2799.              |Unknown| | s[0]  | | s[1]  |   | s[24] | | s[25] | |Unknown|
  2800.      Memory: |+-----+| |+-----+| |+-----+|...|+-----+| |+-----+| |+-----+|
  2801.              || XXX || || "T" || || "h" ||   || "t" || ||  0  || || XXX ||
  2802.              +=======+ +=======+ +=======+   +=======+ +=======+ +=======+
  2803.  
  2804.    E-strings are very similar to normal strings and, in fact, an E-string
  2805. can be used wherever a normal string can.  However, the reverse is not
  2806. true, so if something requires an E-string you cannot use a normal string
  2807. instead.  The difference between a normal string and an E-string was
  2808. hinted at in the introduction to this section: E-strings can be safely
  2809. altered without exceeding their bounds.  A normal string is just an array
  2810. so you need to be careful not to exceed its bounds.  However, an E-string
  2811. knows what its bounds are, and so any of the string manipulation functions
  2812. can alter them safely.
  2813.  
  2814.    An E-string (STRING type) variable is declared as in the following
  2815. example, with the maximum size of the E-string given just like an array
  2816. declaration.
  2817.  
  2818.        DEF s[30]:STRING
  2819.  
  2820. As with an array declaration, the variable s is actually a pointer to the
  2821. string data.  To initialise an E-string you need to use the function
  2822. StrCopy as we shall see.
  2823.  
  2824. ========================================================================
  2825.  
  2826.  
  2827. String functions
  2828. ----------------
  2829.  
  2830.    There are a number of useful built-in functions which manipulate
  2831. strings.  Remember that if an E-string can be used wherever a normal
  2832. string can, but normal strings cannot be used where an E-string is
  2833. required.  If a parameter is marked as string then a normal or E-string
  2834. can be passed as that parameter, but if it is marked as e-string then only
  2835. an E-string may be used.
  2836.  
  2837. String(maxsize)
  2838.      Allocates memory for an E-string of maximum size maxsize and returns
  2839.      a pointer to the string data.  It is used to make space for a new
  2840.      E-string, like a STRING declaration does.  The following code
  2841.      fragments are practically equivalent:
  2842.  
  2843.             DEF s[37]:STRING
  2844.           
  2845.             DEF s:PTR TO CHAR
  2846.             s:=String(37)
  2847.  
  2848.      The slight difference is that there may not be enough memory left to
  2849.      hold the E-string when the String function is used.  In that case the
  2850.      special value NIL (a constant) is returned.  Your program must check
  2851.      that the value returned is not NIL before you use it as an E-string
  2852.      (or dereference it).  The memory for the declaration version is
  2853.      allocated when the program is run, so your program won't run if there
  2854.      isn't enough memory.  The String version is often called dynamic
  2855.      allocation because it happens only when the program is running; the
  2856.      declaration version has allocation done by the E compiler.
  2857.  
  2858. StrCmp(string1,string2,length)
  2859.      Compares string1 with string2 (they can both be normal or E-strings).
  2860.      Returns TRUE if the first length characters of the strings match, and
  2861.      FALSE otherwise.  The length can be the special constant ALL which
  2862.      means that the strings must agree on every character.  For example,
  2863.      the following comparisons all return TRUE:
  2864.  
  2865.             StrCmp('ABC',  'ABC',    ALL)
  2866.             StrCmp('ABCd', 'ABC',    3)
  2867.             StrCmp('ABCde','ABCxxjs',3)
  2868.  
  2869.      And the following return FALSE (notice the case of the letters):
  2870.  
  2871.             StrCmp('ABC',  'ABc', ALL)
  2872.             StrCmp('ABCd', 'ABC', ALL)
  2873.  
  2874. StrCopy(e-string,string,length)
  2875.      Copies the contents of string to e-string.  Only length characters
  2876.      are copied from the source string, but the special constant ALL can
  2877.      be used to indicate that the whole of the source string is to be
  2878.      copied.  Remember that E-strings are safely manipulated, so the
  2879.      following code fragment results in s becoming More th, since its
  2880.      maximum size is (from its declaration) seven characters.
  2881.  
  2882.             DEF s[7]:STRING
  2883.             StrCopy(s, 'More than seven characters', ALL)
  2884.  
  2885.      A declaration using STRING (or ARRAY) reserves a small part of
  2886.      memory, and stores a pointer to this memory in the variable being
  2887.      declared.  So to get data into this memory you need to copy it there,
  2888.      using StrCopy.  If you're familiar with very high-level languages
  2889.      like BASIC you should take care, because you might think you can
  2890.      assign a string to an array or an E-string variable.  In E (and
  2891.      languages like C and Assembly) you must explicitly copy data into
  2892.      arrays and E-strings.  You should not do the following:
  2893.  
  2894.             /* You don't want to do things like this! */
  2895.             DEF s[80]:STRING
  2896.             s:='This is a string constant'
  2897.  
  2898.      This is fairly disastrous: it throws away the pointer to reserved
  2899.      memory that was stored in s and replaces it by a pointer to the
  2900.      string constant.  s is then no longer an E-string, and cannot be
  2901.      repaired using StrLen.  If you want s to contain the above string you
  2902.      must use StrCopy:
  2903.  
  2904.             DEF s[80]:STRING
  2905.             StrCopy(s,'This is a string constant',ALL)
  2906.  
  2907.      The moral is: remember when you are using pointers to data and when
  2908.      you need to copy data.  Also, remember that assignment does not copy
  2909.      large arrays of data, it only copies pointers to data, so if you want
  2910.      to store some data in an ARRAY or STRING type variable you need to
  2911.      copy it there.
  2912.  
  2913. StrAdd(e-string,string,length)
  2914.      This does the same as StrCopy but the source string is copied onto
  2915.      the end of the destination E-string.  The following code fragment
  2916.      results in s becoming This is a string and a half.
  2917.  
  2918.             DEF s[30]:STRING
  2919.             StrCopy(s, 'This is a string', ALL)
  2920.             StrAdd(s,  ' and a half',      ALL)
  2921.  
  2922. StrLen(string)
  2923.      Returns the length of string.  This assumes that the string is
  2924.      terminated by a null character (i.e., ASCII zero), which is true for
  2925.      any strings made from E-strings and string constants.  However, you
  2926.      can make a string constant look short if you use the null character
  2927.      (the special sequence \0) in it.  For instance, these calls all
  2928.      return three:
  2929.  
  2930.             StrLen('abc')
  2931.             StrLen('abc\0def')
  2932.  
  2933.      In fact, most of the string functions assume strings are
  2934.      null-terminated, so you shouldn't use null characters in your strings
  2935.      unless you really know what you're doing.
  2936.  
  2937.      For E-strings StrLen is less efficient than the EstrLen function.
  2938.  
  2939. EstrLen(e-string)
  2940.      Returns the length of e-string (remember this can only be an
  2941.      E-string).  This is much more efficient than StrLen since E-strings
  2942.      know their length and it doesn't need to search the string for a null
  2943.      character.
  2944.  
  2945. StrMax(e-string)
  2946.      Returns the maximum length of e-string.  This not necessarily the
  2947.      current length of the E-string, rather it is the size used in the
  2948.      declaration with STRING or the call to String.
  2949.  
  2950. RightStr(e-string1,e-string2,length)
  2951.      This is like StrCopy but it copies the right-most characters from
  2952.      e-string2 to e-string1 and both strings must be E-strings.  At most
  2953.      length characters are copied, and the special constant ALL cannot be
  2954.      used (to copy all the string you should, of course, use StrCopy).
  2955.      For instance, a value of one for length means the last character of
  2956.      e-string2 is copied to e-string1.
  2957.  
  2958. MidStr(e-string,string,index,length)
  2959.      Copies the contents of string starting at index (which is an index
  2960.      just like an array index) to e-string.  At most length characters are
  2961.      copied, and the special constant ALL can be used if all the remaining
  2962.      characters in string should be copied.  For example, the following
  2963.      two calls to MidStr result in s becoming four:
  2964.  
  2965.             DEF s[30]:STRING
  2966.             MidStr(s, 'Just four',      5, ALL)
  2967.             MidStr(s, 'Just four, sir', 5, 4)
  2968.  
  2969. InStr(string1,string2,startindex)
  2970.      Returns the index of the first occurrence of string2 in string1
  2971.      starting at startindex (in string1).  If string2 could not be found
  2972.      then -1 is returned.
  2973.  
  2974. TrimStr(string)
  2975.      Returns the address of (i.e., a pointer to) the first non-whitespace
  2976.      character in string.  For instance, the following code fragment
  2977.      results in s becoming 12345.
  2978.  
  2979.             DEF s:PTR TO CHAR
  2980.             s:=TrimStr('  \n \t   12345')
  2981.  
  2982. LowerStr(string)
  2983.      Converts all uppercase letters in string to lowercase.  This change
  2984.      is made in-place, i.e., the contents of the string are directly
  2985.      affected.
  2986.  
  2987. UpperStr(string)
  2988.      Converts all lowercase letters in string to uppercase.  Again, this
  2989.      change is made in-place.
  2990.  
  2991. SetStr(e-string,length)
  2992.      Sets the length of e-string to length.  E-strings know how long they
  2993.      are, so if you alter an E-string (without using an E-string function)
  2994.      and change its size you need to set its length using this function
  2995.      before you can use it as an E-string again.  For instance, if you've
  2996.      used an E-string like an array (which you can do) and written
  2997.      characters to it directly you must set its length before you can
  2998.      treat it as anything other than an array/string:
  2999.  
  3000.             DEF s[10]:STRING
  3001.             s[0]:="a"     /* Remember that "a" is a character value. */
  3002.             s[1]:="b"
  3003.             s[2]:="c"
  3004.             s[3]:="d"     /* At this point s is just an array of CHAR. */
  3005.             SetStr(s, 4)  /* Now, s can be used as an E-string again.  */
  3006.             SetStr(s, 2)  /* s is a bit shorter, but still an E-string.*/
  3007.  
  3008.      Notice that this function can be used to shorten an E-string (but you
  3009.      cannot lengthen it this way).
  3010.  
  3011. Val(string,address)
  3012.      What this function does is straight-forward but how you use it is a
  3013.      bit complicated.  Basically, it converts string to a LONG integer.
  3014.      Leading whitespace is ignored, and a leading % or $ means that the
  3015.      string denotes a binary or hexadecimal integer (in the same way they
  3016.      do for numeric constants).  The decoded integer is returned.  The
  3017.      number of characters of string that were read to make the integer is
  3018.      stored at address, which is usually a variable address (from using
  3019.      {var }).  If address is the special constant NIL (or zero) then
  3020.      this number is not stored.  You can use this number to calculate the
  3021.      position in the string which was not part of the integer in the
  3022.      string.  If an integer could not be decoded from the string then zero
  3023.      is returned and zero is stored at address.
  3024.  
  3025.      Follow the comments in this example, and pay special attention to the
  3026.      use of the pointer p.
  3027.  
  3028.             DEF s[30]:STRING, value, chars, p:PTR TO CHAR
  3029.             StrCopy(s, ' \t \n 10 \t $3F -%0101010', ALL)
  3030.             value:=Val('abcde 10 20', {chars})
  3031.               /* After the above line, value and chars will both be zero */
  3032.             value:=Val(s, {chars})
  3033.               /* Now value will be 10, chars will be 7 */
  3034.             p:=s+chars
  3035.               /* p now points to the space after the 10 in s */
  3036.             value:=Val(p, {chars})
  3037.               /* Now value will be $3F (63), chars will be 6 */
  3038.             p:=p+chars
  3039.               /* p now points to the space after the $3F in s */
  3040.             value:=Val(p, {chars})
  3041.               /* Now value will be -%0101010 (-42), chars will be 10 */
  3042.  
  3043.    There's a couple of other string functions (ReadStr and StringF) which
  3044. will be discussed later (see Input and output functions).
  3045.  
  3046. ========================================================================
  3047.  
  3048.  
  3049. Lists and E-lists
  3050. -----------------
  3051.  
  3052.    Lists are just like strings with LONG elements rather than CHAR
  3053. elements (so they are very much like ARRAY OF LONG).  The list equivalent
  3054. of an E-string is something called an E-list.  It has the same properties
  3055. as an E-string, except the elements are LONG (so could be pointers).
  3056. Normal lists are most like string constants, except that the elements can
  3057. be built from variables and so do not have to be constants.  Just as
  3058. strings are not true E-strings, (normal) lists are not true E-lists.
  3059.  
  3060.    Lists are written using [ and ] to delimit comma separated elements.
  3061. Like string constants a list returns the address of the memory which
  3062. contains the elements.
  3063.  
  3064.    For example the following code fragment:
  3065.  
  3066.        DEF list:PTR TO LONG, number
  3067.        number:=22
  3068.        list:=[1,2,3,number]
  3069.  
  3070. is equivalent to:
  3071.  
  3072.        DEF list[4]:ARRAY OF LONG, number
  3073.        number:=22
  3074.        list[0]:=1
  3075.        list[1]:=2
  3076.        list[2]:=3
  3077.        list[3]:=number
  3078.  
  3079. Now, which of these two versions would you rather write?  As you can see,
  3080. lists are pretty useful for making your program easier to write and much
  3081. easier to read.
  3082.  
  3083.    E-list variables are like E-string variables and are declared in much
  3084. the same way.  The following code fragment declares lt to be an E-list of
  3085. maximum size 30.  As ever, lt is then a pointer (to LONG), and it points
  3086. to the memory allocated by the declaration.
  3087.  
  3088.        DEF lt[30]:LIST
  3089.  
  3090.    Lists are most useful for writing tag lists, which are increasingly
  3091. used in important Amiga system functions.  A tag list is a list where the
  3092. elements are thought of in pairs.  The first element of a pair is the tag,
  3093. and the second is some data for that tag.  See the `Rom Kernel Reference
  3094. Manual (Libraries)' for more details.
  3095.  
  3096. ========================================================================
  3097.  
  3098.  
  3099. List functions
  3100. --------------
  3101.  
  3102.    There are a number of list functions which are very similar to the
  3103. string functions (see String functions).  Remember that E-lists are the
  3104. list equivalents of E-strings, i.e., they can be altered and extended
  3105. safely without exceeding their bounds.  As with E-strings, E-lists are
  3106. downwardly compatible with lists.  Therefore, if a function requires a
  3107. list as a parameter you can supply a list or an E-list.  But if a function
  3108. requires an E-list you cannot use a list in its place.
  3109.  
  3110. List(maxsize)
  3111.      Allocates memory for an E-list of maximum size maxsize and returns a
  3112.      pointer to the list data.  It is used to make space for a new E-list,
  3113.      like a LIST declaration does.  The following code fragments are (as
  3114.      with String) practically equivalent:
  3115.  
  3116.             DEF lt[46]:LIST
  3117.           
  3118.             DEF lt:PTR TO LONG
  3119.             lt:=List(46)
  3120.  
  3121.      Remember that you need to check that the return value from List is
  3122.      not NIL before you use it as an E-list.
  3123.  
  3124. ListCmp(list1,list2,length)
  3125.      Compares list1 with list2 (they can both be normal or E-lists).
  3126.      Works just like StrCmp does for E-strings, so, for example, the
  3127.      following comparisons all return TRUE:
  3128.  
  3129.             ListCmp([1,2,3,4],   [1,2,3,4], ALL)
  3130.             ListCmp([1,2,3,4],   [1,2,3,7], 3)
  3131.             ListCmp([1,2,3,4,5], [1,2,3],   3)
  3132.  
  3133. ListCopy(e-list,list,length)
  3134.      Works just like StrCopy, and the following example shows how to
  3135.      initialise an E-list:
  3136.  
  3137.             DEF lt[7]:LIST, x
  3138.             x:=4
  3139.             ListCopy(lt, [1,2,3,x], ALL)
  3140.  
  3141.      As with StrCopy, an E-list cannot be over-filled using ListCopy.
  3142.  
  3143. ListAdd(e-list,list,length)
  3144.      Works just like StrAdd, so this next code fragment results in the
  3145.      E-list lt becoming the E-list version of [1,2,3,4,5,6,7,8].
  3146.  
  3147.             DEF lt[30]:LIST
  3148.             ListCopy(lt, [1,2,3,4], ALL)
  3149.             ListAdd(lt, [5,6,7,8], ALL)
  3150.  
  3151. ListLen(list)
  3152.      Works just like StrLen, returning the length of list.  There is no
  3153.      E-list specific length function.
  3154.  
  3155. ListMax(e-list)
  3156.      Works just like StrMax, returning the maximum length of the e-list.
  3157.  
  3158. SetList(e-list,length)
  3159.      Works just like SetStr, setting the length of e-list to length.
  3160.  
  3161. ListItem(list,index)
  3162.      Returns the element of list at index.  For example, if lt is an
  3163.      E-list then ListItem(lt,n) is the same as lt[n].  This function is
  3164.      most useful when the list is not an E-list.  For example, the
  3165.      following two code fragments are equivalent:
  3166.  
  3167.             WriteF(ListItem(['Fred','Barney','Wilma','Betty'], name))
  3168.           
  3169.             DEF lt:PTR TO LONG
  3170.             lt:=['Fred','Barney','Wilma','Betty']
  3171.             WriteF(lt[name])
  3172.  
  3173. ========================================================================
  3174.  
  3175.  
  3176. Complex types
  3177. -------------
  3178.  
  3179.    In E the STRING and LIST types are called complex types.  Complex typed
  3180. variables can also be created using the String and List functions as we've
  3181. seen in the previous sections.
  3182.  
  3183. ========================================================================
  3184.  
  3185.  
  3186. Typed lists
  3187. -----------
  3188.  
  3189.    Normal lists contain LONG elements, so you can write initialised arrays
  3190. of LONG elements.  What about other kinds of array?  Well, that's what
  3191. typed lists are for.  You specify the type of the elements of a list using
  3192.  :type after the closing ].  The allowable types are CHAR, INT, LONG and
  3193. any object type.  There is a subtle difference between a normal, LONG list
  3194. and a typed list (even a LONG typed list): only normal lists can be used
  3195. with the list functions (see List functions).  For this reason, the term
  3196. `list' tends to refer only to normal lists.
  3197.  
  3198.    The following code fragment uses the object rec defined earlier (see
  3199. Example object) and gives a couple of examples of typed lists:
  3200.  
  3201.        DEF ints:PTR TO INT, objects:PTR TO rec, p:PTR TO CHAR
  3202.        ints:=[1,2,3,4]:INT
  3203.        p:='fred'
  3204.        objects:=[1,2,p,4,
  3205.                  300,301,'barney',303]:rec
  3206.  
  3207. It is equivalent to:
  3208.  
  3209.        DEF ints[4]:ARRAY OF INT, objects[2]:ARRAY OF rec, p:PTR TO CHAR
  3210.        ints[0]:=1
  3211.        ints[1]:=2
  3212.        ints[2]:=3
  3213.        ints[3]:=4
  3214.        p:='fred'
  3215.        objects[0].tag:=1
  3216.        objects[0].check:=2
  3217.        objects[0].table:=p
  3218.        objects[0].data:=4
  3219.        objects[1].table:='barney'
  3220.        objects[1].tag:=300
  3221.        objects[1].data:=303
  3222.        objects[1].check:=301
  3223.  
  3224.    The last group of assignments to objects[1] have deliberately been
  3225. shuffled in order to emphasise that the order of the elements in the
  3226. definition of the object rec is significant.  Each of the elements of the
  3227. list corresponds to an element in the object, and the order of elements in
  3228. the list corresponds to the order in the object definition.  In the
  3229. example, the (object) list assignment line was broken after the end of the
  3230. first object (the fourth element) to make it a bit more readable.  The
  3231. last object in the list need not be completely defined, so, for instance,
  3232. the second line of the assignment could have contained only three elements.
  3233.  
  3234. ========================================================================
  3235.  
  3236.  
  3237. Static data
  3238. -----------
  3239.  
  3240.    String constants (e.g., fred), lists (e.g., [1,2,3]) and typed lists
  3241. (e.g., [1,2,3]:INT) are static data.  This means that the address of the
  3242. (initialised) data is fixed when the program is run.  Normally you don't
  3243. need to worry about this, but, for instance, if you want to have a series
  3244. of lists as initialised arrays you might be tempted to use some kind of
  3245. loop:
  3246.  
  3247.      PROC main()
  3248.        DEF i, a[10]:ARRAY OF LONG, p:PTR TO LONG
  3249.        FOR i:=0 TO 9
  3250.          a[i]:=[1, i, i*i]
  3251.            /* This assignment is probably not what you want! */
  3252.        ENDFOR
  3253.        FOR i:=0 TO 9
  3254.          p:=a[i]
  3255.          WriteF('a[\d] is an array at address \d\n', i, p)
  3256.          WriteF('  and the second element is \d\n', p[1])
  3257.        ENDFOR
  3258.      ENDPROC
  3259.  
  3260. The array a is an array of pointers to initialised arrays (which are all
  3261. three elements long).  But, as the comment suggests and the program shows,
  3262. this probably doesn't do what was intended, since the list is static.
  3263. That means the address of the list is fixed, so each element of a gets the
  3264. same address (i.e., the same array).  Since i is used in the list the
  3265. contents of that part of memory varies slightly as the first FOR loop is
  3266. processed.  But after this loop the contents remain fixed, and the second
  3267. element of each of the ten arrays is always nine.  This is an example of
  3268. the output that will be generated (the ... represents a number of similar
  3269. lines):
  3270.  
  3271.      a[0] is an array at address 4021144
  3272.        and the second element is 9
  3273.      a[1] is an array at address 4021144
  3274.        and the second element is 9
  3275.      ...
  3276.      a[9] is an array at address 4021144
  3277.        and the second element is 9
  3278.  
  3279. The solution is to use the dynamic allocation function List and copy the
  3280. normal list into the new E-list using ListCopy:
  3281.  
  3282.      PROC main()
  3283.        DEF i, a[10]:ARRAY OF LONG, p:PTR TO LONG
  3284.        FOR i:=0 TO 9
  3285.          a[i]:=List(3)
  3286.          /* Must check that the allocation succeeded before copying */
  3287.          IF a[i]<>NIL THEN ListCopy(a[i], [1, i, i*i], ALL)
  3288.        ENDFOR
  3289.        FOR i:=0 TO 9
  3290.          p:=a[i]
  3291.          IF p=NIL
  3292.            WriteF('Could not allocate memory for a[\d]\n', i)
  3293.          ELSE
  3294.            WriteF('a[\d] is an array at address \d\n', i, p)
  3295.            WriteF('  and the second element is \d\n', p[1])
  3296.          ENDIF
  3297.        ENDFOR
  3298.      ENDPROC
  3299.  
  3300.    The problem is not so bad with string constants, since the contents are
  3301. fixed.  However, if you alter the contents explicitly, you will need to
  3302. take care not to run into the same problem, as this next example shows.
  3303.  
  3304.      PROC main()
  3305.        DEF i, strings[10]:ARRAY OF LONG, s:PTR TO CHAR
  3306.        FOR i:=0 TO 9
  3307.          strings[i]:='Hello World\n'
  3308.            /* This assignment is probably not what you want! */
  3309.        ENDFOR
  3310.        s:=strings[4]
  3311.        s[5]:="X"
  3312.        FOR i:=0 TO 9
  3313.          WriteF('strings[\d] is ', i)
  3314.          WriteF(strings[i])
  3315.        ENDFOR
  3316.      ENDPROC
  3317.  
  3318. This is an example of the output that will be generated (again, the ...
  3319. represents a number of similar lines)::
  3320.  
  3321.      strings[0] is HelloXWorld
  3322.      strings[1] is HelloXWorld
  3323.      ...
  3324.      strings[9] is HelloXWorld
  3325.  
  3326. Again, the solution is to use dynamic allocation.  The functions String
  3327. and StrCopy should be used in the same way that List and ListCopy were
  3328. used above.
  3329.  
  3330. ========================================================================
  3331.  
  3332.  
  3333. Linked Lists
  3334. ============
  3335.  
  3336.    E-lists and E-strings have a useful extension: they can be used to make
  3337. linked lists.  These are like the lists we've seen already, except the
  3338. list elements do not occupy a contiguous block of memory.  Instead, each
  3339. element has an extra piece of data: a pointer to the next element in the
  3340. list.  This means that each element can be anywhere in memory.  (Normally,
  3341. the next element of a list is in the next position in memory.) The end of
  3342. a linked list has been reached when the pointer to the next element is the
  3343. special value NIL (a constant).  You need to be very careful to check that
  3344. the pointer is not NIL because if it is and you dereference it the program
  3345. will most definitely crash.
  3346.  
  3347.    The elements of a linked list are E-lists or E-strings (i.e., the
  3348. elements are complex typed).  So, you can link E-lists to get a `linked
  3349. list of E-lists' (or, more simply, a `list of lists').  Similarly, linking
  3350. E-strings gives `linked list of E-strings', or a `list of strings'.  You
  3351. don't have to stick to these two kinds of linked lists, though: you can
  3352. use a mixture of E-lists and E-strings in the same linked list.  To link
  3353. one complex typed element to another you use the Link function and to find
  3354. subsequent elements in a linked list you use the Next or Forward functions.
  3355.  
  3356. Link(complex1,complex2)
  3357.      Links complex1 to complex2.  Both must be an E-list or an E-string,
  3358.      with the exception that complex2 can be the special constant NIL to
  3359.      indicate that complex1 is the end of the linked list.  The value
  3360.      complex1 is returned by the function, which isn't always useful so,
  3361.      usually, calls to Link will be used as statements rather than
  3362.      functions.  The effect of Link is that complex1 will point to
  3363.      complex2 as the next element in the linked list (so complex1 is
  3364.      the head of the list, and complex2 is the tail).  For both E-lists
  3365.      and E-strings the pointer to the next element is initially NIL, so
  3366.      you will only need to use Link with a NIL parameter when you want to
  3367.      make a linked list shorter (by losing the tail).
  3368.  
  3369. Next(complex)
  3370.      Returns the pointer to the next element in the linked list.  This may
  3371.      be the special constant NIL if complex is the last element in the
  3372.      linked list.  Be careful to check that the value isn't NIL before you
  3373.      dereference it!  Follow the comments in the example below:
  3374.  
  3375.             DEF s[23]:STRING, t[7]:STRING, lt[41]:LIST, lnk
  3376.             /* The next two lines set up the linked list "lnk" */
  3377.             lnk:=Link(lt,t)  /* lnk list starts at lt and is lt->t    */
  3378.             lnk:=Link(s,lt)  /*   Now it starts at s  and is s->lt->t */
  3379.             /* The next three lines follow the links in "lnk"  */
  3380.             lnk:=Next(lnk)   /*   Now it starts at lt and is lt->t    */
  3381.             lnk:=Next(lnk)   /*   Now it starts at t  and is t        */
  3382.             lnk:=Next(lnk)   /* Now lnk is NIL so the list has ended  */
  3383.  
  3384.      You may safely call Next with a NIL parameter, and in this case it
  3385.      will return NIL.
  3386.  
  3387. Forward(complex,expression)
  3388.      Returns a pointer to the element which is expression number of links
  3389.      down the linked list complex.  If expression represents the value one
  3390.      a pointer to the next element is returned (just like using Next).  If
  3391.      it's two a pointer to the element after that is returned.
  3392.  
  3393.      If expression represents a number which is greater than the number of
  3394.      links in the list the special value NIL is returned.
  3395.  
  3396.    Since the link in a linked list is a pointer to the next element you
  3397. can only look through the list from beginning to end.  Technically this is
  3398. singly linked list (a doubly linked list would also have a pointer to
  3399. the previous element in the list, enabling backwards searching through the
  3400. list).
  3401.  
  3402.    Linked lists are useful for building lists that can grow quite large.
  3403. This is because it's much better to have lots of small bits of memory than
  3404. a large lump.  However, you only need to worry about these things when
  3405. you're playing with quite big lists (as a rough guide, ones with over
  3406. 100,000 elements are big!).
  3407.  
  3408. ========================================================================
  3409.  
  3410.  
  3411. More About Statements and Expressions
  3412. *************************************
  3413.  
  3414.    This chapter details various E statements and expressions that were not
  3415. covered in Part One.  It also completes some of the partial descriptions
  3416. given in Part One.
  3417.  
  3418. Next:
  3419.  
  3420.   Turning an Expression into a Statement  
  3421.   Initialised Declarations  
  3422.   Assignments  
  3423.   More Expressions  
  3424.   More Statements  
  3425.   Quoted Expressions  
  3426.   Assembly Statements  
  3427.  
  3428. ========================================================================
  3429.  
  3430.  
  3431. Turning an Expression into a Statement
  3432. ======================================
  3433.  
  3434.    The VOID operator converts an expression to a statement.  It does this
  3435. by evaluating the expression and then throwing the result away.  This may
  3436. not seem very useful, but in fact we've done it a lot already.  We didn't
  3437. use VOID explicitly because E does this automatically if it finds an
  3438. expression where it was expecting a statement (normally when it is on a
  3439. line by itself).  Some of the expressions we've turned into statements
  3440. were the procedure calls (to WriteF and fred) and the use of ++.  Remember
  3441. that all procedure calls denote values because they're really functions
  3442. that, by default, return zero (see Procedures as Functions).
  3443.  
  3444.    For example, the following code fragments are equivalent:
  3445.  
  3446.        VOID WriteF('Hello world\n')
  3447.        VOID x++
  3448.      
  3449.        WriteF('Hello world\n')
  3450.        x++
  3451.  
  3452. Since E automatically uses VOID it's a bit of a waste of time writing it
  3453. in, although there may be occasions where you want to use it to make this
  3454. voiding process more explicit (to the reader).  The important thing is the
  3455. fact that expressions can validly be used as statements in E.
  3456.  
  3457. ========================================================================
  3458.  
  3459.  
  3460. Initialised Declarations
  3461. ========================
  3462.  
  3463.    Some variables can be initialised using constants in their declarations.
  3464. The variables you cannot initialise in this way are array and complex type
  3465. variables (and procedure parameters, obviously).  All the other kinds can
  3466. be initialised, whether they are local or global.  An initialised
  3467. declaration looks very much like a constant definition, with the value
  3468. following the variable name and a = character joining them.  The following
  3469. example illustrates initialised declarations:
  3470.  
  3471.      SET ENGLISH, FRENCH, GERMAN, JAPANESE, RUSSIAN
  3472.      
  3473.      CONST FREDLANGS=ENGLISH OR FRENCH OR GERMAN
  3474.      
  3475.      DEF fredspeak=FREDLANGS,
  3476.          p=NIL:PTR TO LONG, q=0:PTR TO rec
  3477.      
  3478.      PROC fred()
  3479.        DEF x=1, y=88
  3480.        /* Rest of procedure */
  3481.      ENDPROC
  3482.  
  3483. Notice how the constant FREDLANGS needs to be defined in order to
  3484. initialise the declaration of fredspeak to something mildly complicated.
  3485. Also, notice the initialisation of the pointers p and q, and the position
  3486. of the type information.
  3487.  
  3488.    Of course, if you want to initialise variables with anything more
  3489. complicated than a constant you can use assignments at the start of the
  3490. code.  Generally, you should always initialise your variables (using
  3491. either method) so that they are guaranteed to have a sensible value when
  3492. you use them.  Using the value of a variable that you haven't initialised
  3493. in some way will probably get you in to a lot of trouble, because the
  3494. value will just be some random value that happened to be in the memory
  3495. used by the variable.  There are rules for how E initialises some kinds of
  3496. variables (see the `Reference Manual', but it's wise to explicitly
  3497. initialise even those, as (strangely enough!) this will make your program
  3498. more readable.
  3499.  
  3500. ========================================================================
  3501.  
  3502.  
  3503. Assignments
  3504. ===========
  3505.  
  3506.    We've already seen some assignments--these were assignment statements.
  3507. Assignment expressions are similar except (as you've guessed) they can be
  3508. used in expressions.  This is because they return the value on the
  3509. right-hand side of the assignment as well as performing the assignment.
  3510. This is useful for efficiently checking that the value that's been
  3511. assigned is sensible.  For instance, the following code fragments are
  3512. equivalent, but the first uses an assignment expression instead of a
  3513. normal assignment statement.
  3514.  
  3515.        IF (x:=y*z)=0
  3516.          WriteF('Error: y*z is zero (and x is zero)\n')
  3517.        ELSE
  3518.          WriteF('OK: y*z is not zero (and x is y*z)\n')
  3519.        ENDIF
  3520.      
  3521.        x:=y*z
  3522.        IF x=0
  3523.          WriteF('Error: y*z is zero (and x is zero)\n')
  3524.        ELSE
  3525.          WriteF('OK: y*z is not zero (and x is y*z)\n')
  3526.        ENDIF
  3527.  
  3528. You can easily tell the assignment expression: it's in parentheses and not
  3529. on a line by itself.  Notice the use of parentheses to group the
  3530. assignment expression.  Technically, the assignment operator has a very
  3531. low precedence.  Untechnically, it will take as much as it can of the
  3532. right-hand side to form the value to be assigned, so you need to use
  3533. parentheses to stop x getting the value ((y*z)=0) (which will be TRUE or
  3534. FALSE, i.e., -1 or zero).
  3535.  
  3536.    Assignment expressions, however, don't allow as rich a left-hand side
  3537. as assignment statements.  The only thing allowed on the left-hand side of
  3538. an assignment expression is a variable name, whereas the statement form
  3539. allows:
  3540.  
  3541.        var
  3542.        var [ expression ]
  3543.        var . obj_element_name
  3544.        var [ expression ] . obj_element_name
  3545.        ^ var
  3546.  
  3547. And each of these may end with ++ or --.  Therefore, the following are all
  3548. valid assignments (the last three use assignment expressions):
  3549.  
  3550.        x:=2
  3551.        x--:=1
  3552.        x[a*b]:=rubble
  3553.        x.apple++:=3
  3554.        x[22].apple:=y*z
  3555.        x[].pear--:=fred(2,4)
  3556.      
  3557.        x:=(y:=2)
  3558.        x[y*z].orange:=(IF (y:=z)=2 THEN 77 ELSE 33)
  3559.        WriteF('x is now \d\n', x:=1+(y:=(z:=fred(3,5)/2)*8))
  3560.  
  3561. You may be wondering what the ++ or -- affect.  Well, it's very simple:
  3562. they only affect the var, which is x in all of the examples above.  Notice
  3563. that x[].pear-- is the same as x.pear--, for the same reasons mentioned
  3564. earlier (see Element types).
  3565.  
  3566. ========================================================================
  3567.  
  3568.  
  3569. More Expressions
  3570. ================
  3571.  
  3572.    This section discusses side-effects, details two new operators (BUT and
  3573. SIZEOF) and completes the description of the AND and OR operators.
  3574.  
  3575. Next:
  3576.  
  3577.   Side-effects  
  3578.   BUT expression  
  3579.   Bitwise AND and OR  
  3580.   SIZEOF expression  
  3581.  
  3582. ========================================================================
  3583.  
  3584.  
  3585. Side-effects
  3586. ------------
  3587.  
  3588.    If evaluating an expression causes the contents of variables to change
  3589. then that expression is said to have side-effects.  An assignment
  3590. expression is a simple example of an expression with side-effects.  Less
  3591. obvious ones involve function calls with pointers to variables.
  3592. Generally, expressions with side-effects should be avoided unless it is
  3593. really obvious what is happening.  This is because it can be difficult to
  3594. find problems with your program's code if subtleties are buried in
  3595. complicated expressions.  On the other hand, side-effecting expressions
  3596. are concise and often very elegant.  They are also useful for obfuscating
  3597. your code (i.e., making it difficult to understand--a form of copy
  3598. protection!).
  3599.  
  3600. ========================================================================
  3601.  
  3602.  
  3603. BUT expression
  3604. --------------
  3605.  
  3606.    BUT is used to sequence two expressions.  exp1 BUT exp2 evaluates exp1,
  3607. and then evaluates and returns the value of exp2.  This may not seem very
  3608. useful at first sight, but if the first expression is an assignment it
  3609. allows for a more general assignment expression.  For example, the
  3610. following code fragments are equivalent:
  3611.  
  3612.        fred((x:=12*3) BUT x+y)
  3613.      
  3614.        x:=12*3
  3615.        fred(x+y)
  3616.  
  3617. Notice that parentheses need to be used around the assignment expression
  3618. (in the first fragment) for the reasons given earlier (see Assignments).
  3619.  
  3620. ========================================================================
  3621.  
  3622.  
  3623. Bitwise AND and OR
  3624. ------------------
  3625.  
  3626.    As hinted in the earlier chapters, the operators AND and OR are not
  3627. simply logical operators.  In fact, they are both bit-wise operators,
  3628. where a bit is a binary digit (i.e., the zeroes or ones in the binary form
  3629. of a number).  So, to see how they work we should look at what happens to
  3630. zeroes and ones:
  3631.  
  3632.       x  y   x OR y  x AND y
  3633.      ------------------------
  3634.       1  1     1        1
  3635.       1  0     1        0
  3636.       0  1     1        0
  3637.       0  0     0        0
  3638.  
  3639.    Now, when you AND or OR two numbers the corresponding bits (binary
  3640. digits) of the numbers are compared individually, according to the above
  3641. table.  So if x were %0111010 and y were %1010010 then x AND y would be
  3642. %0010010 and x OR y would be %1111010:
  3643.  
  3644.              %0111010        %0111010
  3645.            AND             OR
  3646.              %1010010        %1010010
  3647.               -------         -------
  3648.              %0010010        %1111010
  3649.  
  3650. The numbers (in binary form) are lined up above each other, just like you
  3651. do additions with normal numbers (i.e., starting with the right-hand
  3652. digits, and maybe padding with zeroes on the left-hand side).  The two
  3653. bits in each column are AND-ed or OR-ed to give the result below the
  3654. dashed line.
  3655.  
  3656.    So, how does this work for TRUE and FALSE and logic operations?  Well,
  3657. FALSE is the number zero, so all the bits of FALSE are zeroes, and TRUE is
  3658. -1, which is has all 32 bits as ones (these numbers are LONG so they are
  3659. 32-bit quantities).  So AND-ing and OR-ing these values always gives
  3660. numbers which have all zero bits (i.e., FALSE) or all one bits (i.e.,
  3661. TRUE), as appropriate.  It's only when you start mixing numbers that
  3662. aren't zero or -1 that you can muck up the logic.  The non-zero numbers
  3663. one and four are (by themselves) considered to be TRUE, but 4 AND 1 is
  3664. %100 AND %001 which is zero (i.e., FALSE).  So when you use AND as the
  3665. logical operator it's not strictly true that all non-zero numbers
  3666. represent TRUE.  OR does not give such problems so all non-zero numbers
  3667. are treated as TRUE.  Run this example to see why you should be careful:
  3668.  
  3669.      PROC main()
  3670.        test(TRUE,          'TRUE\t\t')
  3671.        test(FALSE,         'FALSE\t\t')
  3672.        test(1,             '1\t\t')
  3673.        test(4,             '4\t\t')
  3674.        test(TRUE OR TRUE,  'TRUE OR TRUE\t')
  3675.        test(TRUE AND TRUE, 'TRUE AND TRUE\t')
  3676.        test(1 OR 4,        '1 OR 4\t\t')
  3677.        test(1 AND 4,       '1 AND 4\t\t')
  3678.      ENDPROC
  3679.      
  3680.      PROC test(x, title)
  3681.        WriteF(title)
  3682.        WriteF(IF x THEN ' is TRUE\n' ELSE ' is FALSE\n')
  3683.      ENDPROC
  3684.  
  3685. Here's the output that should be generated:
  3686.  
  3687.      TRUE             is TRUE
  3688.      FALSE            is FALSE
  3689.      1                is TRUE
  3690.      4                is TRUE
  3691.      TRUE OR TRUE     is TRUE
  3692.      TRUE AND TRUE    is TRUE
  3693.      1 OR 4           is TRUE
  3694.      1 AND 4          is FALSE
  3695.  
  3696.    So, AND and OR are primarily bit-wise operators, and they can be used
  3697. as logical operators under most circumstances, with zero representing
  3698. false and all other numbers representing true.  Care must be taken when
  3699. using AND with some pairs of non-zero numbers, since the bit-wise AND of
  3700. such numbers does not always give a non-zero (or true) result.
  3701.  
  3702. ========================================================================
  3703.  
  3704.  
  3705. SIZEOF expression
  3706. -----------------
  3707.  
  3708.    SIZEOF returns the size, in bytes, of an object.  This can be useful
  3709. for determining storage requirements.  For instance, the following code
  3710. fragment prints the size of the object rec:
  3711.  
  3712.      OBJECT rec
  3713.        tag, check
  3714.        table[8]:ARRAY
  3715.        data:LONG
  3716.      ENDOBJECT
  3717.      
  3718.      PROC main()
  3719.        WriteF('Size of rec object is \d bytes\n', SIZEOF rec)
  3720.      ENDPROC
  3721.  
  3722.    You may think that SIZEOF is unnecessary because you can easily
  3723. calculate the size of an object just by looking at the sizes of the
  3724. elements.  Whilst this is generally true (it was for the rec object),
  3725. there is one thing to be careful about: alignment.  This means that ARRAY,
  3726. INT, LONG and object typed elements must start at an even memory address.
  3727. Normally this isn't a problem, but if you have an odd number of
  3728. consecutive CHAR typed elements or an odd sized ARRAY, an extra, pad byte
  3729. is introduced into the object so that the following element is aligned
  3730. properly.  This pad byte can be considered part of an ARRAY, so in effect
  3731. this means array sizes are rounded up to the nearest even number.
  3732. Otherwise, pad bytes are just an unusable part of an object, and their
  3733. presence means the object size is not quite what you'd expect.  Try the
  3734. following program:
  3735.  
  3736.      OBJECT rec2
  3737.        tag, check
  3738.        table[7]:ARRAY
  3739.        data:LONG
  3740.      ENDOBJECT
  3741.      
  3742.      PROC main()
  3743.        WriteF('Size of rec2 object is \d bytes\n', SIZEOF rec2)
  3744.      ENDPROC
  3745.  
  3746. The only difference between the rec and rec2 objects is that the array
  3747. size is seven in rec2.  If you run the program you'll see that the size of
  3748. the object has not changed.  We might just as well have declared the table
  3749. element to be a slightly bigger array (i.e., have eight elements).
  3750.  
  3751. ========================================================================
  3752.  
  3753.  
  3754. More Statements
  3755. ===============
  3756.  
  3757.    This section details four new statements (INC, DEC, JUMP and LOOP) and
  3758. describes the use of labelling.
  3759.  
  3760. Next:
  3761.  
  3762.   INC and DEC statements  
  3763.   Labelling and the JUMP statement  
  3764.   LOOP block  
  3765.  
  3766. ========================================================================
  3767.  
  3768.  
  3769. INC and DEC statements
  3770. ----------------------
  3771.  
  3772.    INC x is the same as the statement x:=x+1.  However, because it doesn't
  3773. do an addition it's a bit more efficient.  Similarly, DEC x is the same as
  3774. x:=x-1.
  3775.  
  3776.    The observant reader may think that INC and DEC are the same as ++ and
  3777. --.  But there's one important difference: INC x always increases x by
  3778. one, whereas x++ may increase x by more than one depending on the type to
  3779. which x points.  For example, if x were a pointer to INT then x++ would
  3780. increase x by two (INT is 16-bit, which is two bytes).
  3781.  
  3782. ========================================================================
  3783.  
  3784.  
  3785. Labelling and the JUMP statement
  3786. --------------------------------
  3787.  
  3788.    A label names a position in a program, and these names are global (they
  3789. can be used in any procedure).  The most common use of label is with the
  3790. JUMP statement, but you can also use labels to mark the position of some
  3791. data (see Assembly Statements).  To define a label you write a name
  3792. followed by a colon immediately before the position you want to mark.
  3793. This must be just before the beginning of a statement, either on the
  3794. previous line (by itself) or the start of the same line.
  3795.  
  3796.    The JUMP statement makes execution continue from the position marked by
  3797. a label.  This position must be in the same procedure, but it can be, for
  3798. instance, outside of a loop (and the JUMP will then have terminated that
  3799. loop).  For example, the following code fragments are equivalent:
  3800.  
  3801.        x:=1
  3802.        y:=2
  3803.        JUMP rubble
  3804.        x:=9999
  3805.        y:=1234
  3806.      rubble:
  3807.        z:=88
  3808.      
  3809.        x:=1
  3810.        y:=2
  3811.        z:=88
  3812.  
  3813. As you can see the JUMP statement has caused the second group of
  3814. assignments to x and y to be skipped.  A more useful example uses JUMP to
  3815. help terminate a loop:
  3816.  
  3817.        x:=1
  3818.        y:=2
  3819.        WHILE x<10
  3820.          IF y<10
  3821.            WriteF('x is \d, y is \d\n', x, y)
  3822.          ELSE
  3823.            JUMP end
  3824.          ENDIF
  3825.          x:=x+2
  3826.          y:=y+2
  3827.        ENDWHILE
  3828.      end:
  3829.        WriteF('Finished!\n')
  3830.  
  3831. This loop terminates if x is not less than ten (the WHILE check), or if y
  3832. is not less than ten (the JUMP in the IF block).  This may seem pretty
  3833. familiar, because it's practically the same as an example earlier (see
  3834. WHILE loop).  In fact, it's equivalent to:
  3835.  
  3836.        x:=1
  3837.        y:=2
  3838.        WHILE (x<10) AND (y<10)
  3839.          WriteF('x is \d, y is \d\n', x, y)
  3840.          x:=x+2
  3841.          y:=y+2
  3842.        ENDWHILE
  3843.        WriteF('Finished!\n')
  3844.  
  3845. ========================================================================
  3846.  
  3847.  
  3848. LOOP block
  3849. ----------
  3850.  
  3851.    A LOOP block is a multi-line statement.  It's the general form of loops
  3852. like the WHILE loop, and it builds a loop with no check.  So, this kind of
  3853. loop would normally never end.  However, as we now know, you can terminate
  3854. a LOOP block using the JUMP statement.  As an example, the following two
  3855. code fragments are equivalent:
  3856.  
  3857.        x:=0
  3858.        LOOP
  3859.          IF x<100
  3860.            WriteF('x is \d\n', x++)
  3861.          ELSE
  3862.            JUMP end
  3863.          ENDIF
  3864.        ENDLOOP
  3865.      end:
  3866.        WriteF('Finished\n')
  3867.      
  3868.        x:=0
  3869.        WHILE x<100
  3870.          WriteF('x is \d\n', x++)
  3871.        ENDWHILE
  3872.        WriteF('Finished\n')
  3873.  
  3874. ========================================================================
  3875.  
  3876.  
  3877. Quoted Expressions
  3878. ==================
  3879.  
  3880.    Quoted expressions are a powerful feature of the E language, and they
  3881. require quite a bit of advanced knowledge.  Basically, you can quote any
  3882. expression by starting it with the back-quote character ` (be careful not
  3883. to get it mixed up with the quote character ' which is used for strings).
  3884. This quoting action does not evaluate the expression, instead the address
  3885. of the code for the expression is returned.  This address can be used just
  3886. like any other address, so you can, for instance, store it in a variable
  3887. and pass it to procedures.  Of course, at some point you will use the
  3888. address to execute the code and get the value of the expression.
  3889.  
  3890.    The idea of quoted expressions was borrowed from the functional
  3891. programming language Lisp.  Also borrowed were some powerful functions
  3892. which combine lists with quoted expressions to give very concise and
  3893. readable statements.
  3894.  
  3895. Next:
  3896.  
  3897.   Evaluation  
  3898.   Quotable expressions  
  3899.   Lists and quoted expressions  
  3900.  
  3901. ========================================================================
  3902.  
  3903.  
  3904. Evaluation
  3905. ----------
  3906.  
  3907.    When you've quoted an expression you have the address of the code which
  3908. calculates the value of the expression.  To evaluate the expression you
  3909. pass this address to the Eval function.  So now we have a round-about way
  3910. of calculating the value of an expression.
  3911.  
  3912.      PROC main()
  3913.        DEF adr, x, y
  3914.        x:=0; y:=0
  3915.        adr:=`1+(fred(x,1)*8)-y
  3916.        x:=2; y:=7
  3917.        WriteF('The value is \d\n', Eval(adr))
  3918.        x:=1; y:=100
  3919.        WriteF('The value is now \d\n', Eval(adr))
  3920.      ENDPROC
  3921.      
  3922.      PROC fred(a,b) RETURN (a+b)*a+20
  3923.  
  3924. This is the output that should be generated:
  3925.  
  3926.      The value is 202
  3927.      The value is now 77
  3928.  
  3929. This example shows a quite complicated expression being quoted.  The
  3930. address of the expression is stored in the variable adr, and the
  3931. expression is evaluated using Eval in the calls to WriteF.  The values of
  3932. the variables x and y when the expression is quoted are irrelevant--only
  3933. their values each time Eval is used are significant.  Therefore, when Eval
  3934. is used in the second call to WriteF the values of x and y have changed so
  3935. the resulting value is different.
  3936.  
  3937.    Repeatedly evaluating the same expression is the most obvious use of
  3938. quoted expressions.  Another common use is when you want to do the same
  3939. thing for a variety of different expressions.  For example, if you wanted
  3940. to discover the amount of time it takes to calculate the results of
  3941. various expressions it would be best to use quoted expressions, something
  3942. like this:
  3943.  
  3944.      DEF x,y
  3945.      
  3946.      PROC main()
  3947.        x:=999; y:=173
  3948.        time(`x+y,     'Addition')
  3949.        time(`x*y,     'Multiplication')
  3950.        time(`fred(x), 'Procedure call')
  3951.      ENDPROC
  3952.      
  3953.      PROC time(exp, message)
  3954.        WriteF(message)
  3955.        /* Find current time */
  3956.        Eval(exp)
  3957.        /* Find new time and calculate difference, t */
  3958.        WriteF(': time taken \d\n', t)
  3959.      ENDPROC
  3960.  
  3961. This is just the outline of a program--it's not complete so don't bother
  3962. running it.  The complete version is given as a worked example later (see
  3963. Timing Expressions).
  3964.  
  3965. ========================================================================
  3966.  
  3967.  
  3968. Quotable expressions
  3969. --------------------
  3970.  
  3971.    There is no restriction on the kinds of expression you can quote,
  3972. except that you need to be careful about variable scoping.  If you use
  3973. local variables in a quoted expression you can only Eval it within the
  3974. same procedure (so the variables are in scope).  However, if you use only
  3975. global variables you can Eval it in any procedure.  Therefore, if you are
  3976. going to pass a quoted expression to a procedure and do something with it,
  3977. you should use only global variables.
  3978.  
  3979.    A word of warning: Eval does not check to see if the address it's been
  3980. given is really the address of an expression.  You can therefore get in a
  3981. real mess if you pass it, say, the address of a variable using {var }.
  3982. You need to check all uses of things like Eval yourself, because the E
  3983. compiler lets you write things like Eval(x+9), where you probably meant to
  3984. write Eval(`x+9).  That's because you might want the address you pass to
  3985. Eval to be the result of complicated expressions.  So you may have meant
  3986. to pass x+9 as the parameter!
  3987.  
  3988. ========================================================================
  3989.  
  3990.  
  3991. Lists and quoted expressions
  3992. ----------------------------
  3993.  
  3994.    There are several E built-in functions which use lists and quoted
  3995. expressions in powerful ways.  These functions are similar to functional
  3996. programming constructs and, basically, they allow for very readable code,
  3997. which otherwise would require iterative algorithms (i.e., loops).
  3998.  
  3999. MapList(address,list,e-list,quoted-exp)
  4000.      The address is the address of a variable (e.g., {x}), list is a list
  4001.      or E-list (the source), e-list is an E-list variable (the
  4002.      destination), and quoted-exp is the address of an expression which
  4003.      involves the addressed variable (e.g., `x+2).  The effect of the
  4004.      function is to take, in turn, a value from list, store it at address,
  4005.      evaluate the quoted expression and store the result in the
  4006.      destination list.  For example:
  4007.  
  4008.             MapList({y}, [1,2,3,a,99,1+c], lt, `y*y)
  4009.  
  4010.      results in lt taking the value:
  4011.  
  4012.             [1,4,9,a*a,9801,(1+c)*(1+c)]
  4013.  
  4014.      Functional programmers would say that MapList mapped the function
  4015.      (the quoted expression) across the (source) list.
  4016.  
  4017. ForAll(address,list,quoted-exp)
  4018.      Works just like MapList except that the resulting list is not stored.
  4019.      Instead, ForAll returns TRUE if every element of the resulting list
  4020.      is TRUE (i.e., non-zero), and FALSE otherwise.  In this way it
  4021.      decides whether the quoted expression is TRUE for all elements of the
  4022.      source list.  For example, the following are TRUE:
  4023.  
  4024.             ForAll({x}, [1,2,-13,8,0], `x<10)
  4025.             ForAll({x}, [1,2,-13,8,0], `x<=8)
  4026.             ForAll({x}, [1,2,-13,8,0], `x>-20)
  4027.  
  4028.      and these are FALSE:
  4029.  
  4030.             ForAll({x}, [1,2,-13,8,0], `x OR x)
  4031.             ForAll({x}, [1,2,-13,8,0], `x=2)
  4032.             ForAll({x}, [1,2,-13,8,0], `x<>2)
  4033.  
  4034. Exists(address,list,quoted-exp)
  4035.      Works just like ForAll except it returns TRUE if the quoted
  4036.      expression is TRUE (i.e., non-zero) for at least one of the source
  4037.      list elements and FALSE otherwise.  For example, the following are
  4038.      TRUE:
  4039.  
  4040.             Exists({x}, [1,2,-13,8,0], `x<10)
  4041.             Exists({x}, [1,2,-13,8,0], `x=2)
  4042.             Exists({x}, [1,2,-13,8,0], `x>0)
  4043.  
  4044.      and these are FALSE:
  4045.  
  4046.             Exists({x}, [1,2,-13,8,0], `x<-20)
  4047.             Exists({x}, [1,2,-13,8,0], `x=4)
  4048.             Exists({x}, [1,2,-13,8,0], `x>8)
  4049.  
  4050. ========================================================================
  4051.  
  4052.  
  4053. Assembly Statements
  4054. ===================
  4055.  
  4056.    The E language incorporates an assembler so you can write Assembly
  4057. mnemonics as E statements.  You can even write complete Assembly programs
  4058. and compile them using the E compiler.  More powerfully, you can use E
  4059. variables as part of the mnemonics, so you can really mix Assembly
  4060. statements with normal E statements.
  4061.  
  4062.    This is not really the place to discuss Assembly programming, so if you
  4063. plan to use this feature of E you should get yourself a good book,
  4064. preferably on Amiga Assembly.  Remember that the Amiga uses the Motorola
  4065. 68000 CPU, so you need to learn the Assembly language for that CPU.  More
  4066. powerful and newer Amigas use more advanced CPUs (such as the 68020) which
  4067. have extra mnemonics.  Programs written using just 68000 CPU mnemonics
  4068. will work on all Amigas.
  4069.  
  4070.    If you don't know 68000 Assembly language you ought to skip this
  4071. section and just bear in mind that E statements you don't recognise are
  4072. probably Assembly mnemonics.
  4073.  
  4074. Next:
  4075.  
  4076.   Assembly and the E language  
  4077.   Static memory  
  4078.   Things to watch out for  
  4079.  
  4080. ========================================================================
  4081.  
  4082.  
  4083. Assembly and the E language
  4084. ---------------------------
  4085.  
  4086.    You can reference E variables simply by using them in an operand.
  4087. Follow the comments in the next example (the comments are on the same
  4088. lines as the Assembly mnemonics, the other lines are normal E statements):
  4089.  
  4090.      PROC main()
  4091.        DEF x
  4092.        x:=1
  4093.        MOVE.L x,  D0 /* Copy the value in x to register D0      */
  4094.        ADD.L  D0, D0 /* Double the value in D0                  */
  4095.        MOVE.L D0, x  /* Copy the value in D0 back to variable x */
  4096.        WriteF('x is now \d\n', x)
  4097.      ENDPROC
  4098.  
  4099. Constants can also be referenced but you need to precede the constant with
  4100. a #.
  4101.  
  4102.      CONST APPLE=2
  4103.      
  4104.      PROC main()
  4105.        DEF x
  4106.        MOVE.L #APPLE, D0 /* Copy the constant APPLE to register D0 */
  4107.        ADD.L  D0, D0     /* Double the value in D0                 */
  4108.        MOVE.L D0, x      /* Copy the value in D0 to variable x     */
  4109.        WriteF('x is now \d\n', x)
  4110.      ENDPROC
  4111.  
  4112. Labels and procedures can similarly be referenced, but these are
  4113. PC-relative so you can only address them in this way.  The following
  4114. example illustrates this, but doesn't do anything useful:
  4115.  
  4116.      PROC main()
  4117.        DEF x
  4118.        LEA main(PC), A0 /* Copy the address of main to register A0 */
  4119.        MOVE.L A0, x     /* Copy the value in A0 to variable x      */
  4120.        WriteF('x is now \d\n', x)
  4121.      ENDPROC
  4122.  
  4123. You can call Amiga system functions in the same way as you would normally
  4124. in Assembly.  You need to load the A6 register with the appropriate
  4125. library base, load the other registers with appropriate data and then JSR
  4126. to the system routine.  This next example uses the E built-in variable
  4127. intuitionbase and the Intuition library routine DisplayBeep.  When you run
  4128. it the screen flashes (or, with Workbench 2.1 and above, you might get a
  4129. beep or a sampled sound, depending on your Workbench setup).
  4130.  
  4131.      PROC main()
  4132.        MOVE.L #NIL, A0
  4133.        MOVE.L intuitionbase, A6
  4134.        JSR DisplayBeep(A6)
  4135.      ENDPROC
  4136.  
  4137. Unfortunately, this doesn't work in version 2.1b of the E compiler (but it
  4138. does in version 3.0), so you actually need to use the function offset
  4139. values (a good source of these is the `Rom Kernel Reference Manual
  4140. (Includes and Autodocs)', which lists these offsets in small section at
  4141. the back).  Now, DisplayBeep is at offset -$60 in the Intuition library,
  4142. so the above program becomes:
  4143.  
  4144.      PROC main()
  4145.        MOVE.L #NIL, A0
  4146.        MOVE.L intuitionbase, A6
  4147.        JSR -$60(A6)
  4148.      ENDPROC
  4149.  
  4150. ========================================================================
  4151.  
  4152.  
  4153. Static memory
  4154. -------------
  4155.  
  4156.    Assembly programs reserve static memory for things like strings using
  4157. DC mnemonics.  However, these aren't real mnemonics.  They are, in
  4158. fact, compiler directives and they can vary from compiler to compiler.
  4159. The E versions are LONG, INT and CHAR (the type names), which take a list
  4160. of values, reserve the appropriate amount of static memory and fill in
  4161. this memory with the supplied values.  The CHAR form also allows a list of
  4162. characters to be supplied more easily as a string.  In this case, the
  4163. string will automatically be aligned to an even memory location, although
  4164. you are responsible for null-terminating it.  You can also include a whole
  4165. file as static data using INCBIN (and the file named using this statement
  4166. must exist when the program is compiled).  To get at the data you mark it
  4167. with a label.
  4168.  
  4169.    This next example is a bit contrived, but illustrates some static data:
  4170.  
  4171.      PROC main()
  4172.        DEF x:PTR TO CHAR
  4173.        LEA datatable(PC), A0
  4174.        MOVE.L A0, x
  4175.        WriteF(x)
  4176.      ENDPROC
  4177.      
  4178.      datatable:
  4179.        CHAR 'Hello world\n', 0
  4180.      moredata:
  4181.        LONG 1,5,-999,0;    INT -1,222
  4182.        INCBIN 'file.data'; CHAR 0,7,-8
  4183.  
  4184. The Assembly stuff to get the label address is not really necessary, so
  4185. the example could have been just:
  4186.  
  4187.      PROC main()
  4188.        WriteF({datatable})
  4189.      ENDPROC
  4190.      
  4191.      datatable:
  4192.        CHAR 'Hello world\n', 0
  4193.  
  4194. ========================================================================
  4195.  
  4196.  
  4197. Things to watch out for
  4198. -----------------------
  4199.  
  4200.    There are a few things to be aware of when using Assembly with E:
  4201.  
  4202.    * All mnemonics and registers must be in uppercase, whilst, of course,
  4203.      E variables etc., follow the normal E rules.
  4204.  
  4205.    * Most standard Assemblers use ; to mark the rest of the line as a
  4206.      comment.  In E you use the normal /* and */ delimiters.
  4207.  
  4208.    * Registers A4 and A5 are used internally by E, so should not be messed
  4209.      with if you are mixing E and Assembly code.
  4210.  
  4211.    * E function calls like WriteF can affect registers.  Refer to the
  4212.      `Reference Manual' for more details.
  4213.  
  4214. ========================================================================
  4215.  
  4216.  
  4217. E Built-In Constants, Variables and Functions
  4218. *********************************************
  4219.  
  4220.    This chapter describes the constants, variables and functions which are
  4221. built-in to the E language.  You can add more by using modules, but that's
  4222. a more advanced topic (see Modules).
  4223.  
  4224. Next:
  4225.  
  4226.   Built-In Constants  
  4227.   Built-In Variables  
  4228.   Built-In Functions  
  4229.  
  4230. ========================================================================
  4231.  
  4232.  
  4233. Built-In Constants
  4234. ==================
  4235.  
  4236.    We've already met several built-in constants.  Here's the complete list:
  4237.  
  4238. TRUE,  FALSE
  4239.      The boolean constants.  As numbers, TRUE is -1 and FALSE is zero.
  4240.  
  4241. NIL
  4242.      The bad pointer value.  Several functions produce this value for a
  4243.      pointer if an error occurred.  As a number, NIL is zero.
  4244.  
  4245. ALL
  4246.      Used with string and list functions to indicate that all the string
  4247.      or list is to be used.  As a number, ALL is -1.
  4248.  
  4249. GADGETSIZE
  4250.      The minimum number of bytes required to hold all the data for one
  4251.      gadget.  See Intuition support functions.
  4252.  
  4253. OLDFILE,  NEWFILE
  4254.      Used with Open to open an old or new file.  See the `AmigaDOS Manual'
  4255.      for more details.
  4256.  
  4257. STRLEN
  4258.      The length of the last string constant used.  Remember that a string
  4259.      constant is something between ' characters, so, for example, the
  4260.      following program prints the string s and then its length:
  4261.  
  4262.           PROC main()
  4263.             DEF s:PTR TO CHAR, len
  4264.             s:='12345678'
  4265.             len:=STRLEN
  4266.             WriteF(s)
  4267.             WriteF('\nis \d characters long\n', len)
  4268.           ENDPROC
  4269.  
  4270. ========================================================================
  4271.  
  4272.  
  4273. Built-In Variables
  4274. ==================
  4275.  
  4276.    The following variables are built-in to E and are called system
  4277. variables.  They are global so can be accessed from any procedure.
  4278.  
  4279. arg
  4280.      This is a string which contains the command line arguments passed
  4281.      your program when it was run (from the Shell or CLI).  For instance,
  4282.      if your program were called fred and you ran it like this:
  4283.  
  4284.           fred file.txt "a big file" another
  4285.  
  4286.      then arg would the string:
  4287.  
  4288.           file.txt "a big file" another
  4289.  
  4290.      If you have AmigaDOS 2.0 (or greater) you can use the system routine
  4291.      ReadArgs to parse the command line in a much more versatile way.
  4292.      There is a worked example on argument parsing in Part Three (see
  4293.      Argument Parsing).
  4294.  
  4295. wbmessage
  4296.      This contains NIL if your program was started from the Shell/CLI,
  4297.      otherwise it's a pointer to the Workbench message which contains
  4298.      information about the icons selected when you started the program
  4299.      from Workbench.  So, if you started the program from Workbench
  4300.      wbmessage will not be NIL and it will contain the Workbench
  4301.      arguments, but if you started the program from the Shell/CLI
  4302.      wbmessage will be NIL and the argments will be in arg (or via
  4303.      ReadArgs).  There is a worked example on argument parsing in Part
  4304.      Three (see Argument Parsing).
  4305.  
  4306. stdout,  conout
  4307.      These contain the standard output filehandle (which can be standard
  4308.      input, too).  If your program was started from the Shell/CLI they
  4309.      will be filehandles on the Shell/CLI window.  However, if your
  4310.      program was started from Workbench these will normally both be NIL.
  4311.      A call to WriteF will open an output window if they are NIL.  See
  4312.      Input and output functions.
  4313.  
  4314. stdrast
  4315.      The raster port used by E built-in graphics functions such as Box and
  4316.      Plot.  This can be changed so that these functions draw on different
  4317.      screens etc.  See Graphics functions.
  4318.  
  4319. dosbase,  execbase,  gfxbase,  intuitionbase
  4320.      These are pointers to the appropriate library base, and are
  4321.      initialised by the E startup code, i.e., the Dos, Exec, Graphics and
  4322.      Intuition libraries are all opened by E so you don't need to do it
  4323.      yourself.  These libraries are also automatically closed by E, so you
  4324.      shouldn't close them yourself.  However, you must explicitly open and
  4325.      close all other Amiga system libraries that you want to use.  The
  4326.      other library base variables are defined in the accompanying module
  4327.      (see Modules).  Consult the `Reference Manual' for details about the
  4328.      library base variable mathbase.
  4329.  
  4330. ========================================================================
  4331.  
  4332.  
  4333. Built-In Functions
  4334. ==================
  4335.  
  4336.    There are many built-in functions in E. We've already seen a lot of
  4337. string and list functions, and we've used WriteF for printing.  The
  4338. remaining functions are, generally, simplifications of complex Amiga
  4339. system functions, or E versions of support functions found in languages
  4340. like C and Pascal.
  4341.  
  4342.    To understand the graphics and Intuition support functions completely
  4343. you really need to get something like the `Rom Kernel Reference Manual
  4344. (Libraries)'.  However, if you don't want to do anything too complicated
  4345. you can just about get by.
  4346.  
  4347. Next:
  4348.  
  4349.   Input and output functions  
  4350.   Intuition support functions  
  4351.   Graphics functions  
  4352.   Maths and logic functions  
  4353.   System support functions  
  4354.  
  4355. ========================================================================
  4356.  
  4357.  
  4358. Input and output functions
  4359. --------------------------
  4360.  
  4361. WriteF(string,param1,param2,...)
  4362.      Writes a string to the standard output.  If place-holders are used in
  4363.      the string then the appropriate number of parameters must be supplied
  4364.      after the string in the order they are to be printed as part of the
  4365.      string.  So far we've only met the \d place-holder for decimal
  4366.      numbers.  The complete list is:
  4367.  
  4368.           Place-Holder  Parameter Type   Prints
  4369.           -------------------------------------------------
  4370.                \c          Number        Character
  4371.                \d          Number        Decimal number
  4372.                \h          Number        Hexadecimal number
  4373.                \s          String        String
  4374.  
  4375.      So to print a string you use the \s place-holder in the string and
  4376.      supply the string (e.g., a PTR TO CHAR) as a parameter.  Try the
  4377.      following program (remember \a prints an apostrophe character):
  4378.  
  4379.           PROC main()
  4380.             DEF s[30]:STRING
  4381.             StrCopy(s, 'Hello world', ALL)
  4382.             WriteF('The third element of s is "\c"\n', s[2])
  4383.             WriteF('or \d (decimal)\n',                s[2])
  4384.             WriteF('or \h (hexadecimal)\n',            s[2])
  4385.             WriteF('and s itself is \a\s\a\n',         s)
  4386.           ENDPROC
  4387.  
  4388.      This is the output it generates:
  4389.  
  4390.           The third element of s is "l"
  4391.           or 108 (decimal)
  4392.           or 6C (hexadecimal)
  4393.           and s itself is 'Hello world'
  4394.  
  4395.      You can control how the parameter is formatted in the \d, \h and \s
  4396.      fields using another collection of special character sequences before
  4397.      the place-holder and size specifiers after it.  If no size is
  4398.      specified the field will be as big as the data requires.  A fixed
  4399.      field size can be specified using  [number] after the place-holder.
  4400.      For strings you can also use the size specifier  (min,max) which
  4401.      specifies the minimum and maximum sizes of the field.  By default the
  4402.      data is right justified in the field and the left part of the field
  4403.      is filled, if necessary, with spaces.  The following sequences before
  4404.      the place-holder can change this:
  4405.  
  4406.           Sequence        Meaning
  4407.           -----------------------------------
  4408.              \l     Left justify in field
  4409.              \r     Right justify in field
  4410.              \z     Set fill character to "0"
  4411.  
  4412.      See how these formatting controls affect this example:
  4413.  
  4414.           PROC main()
  4415.             DEF s[30]:STRING
  4416.             StrCopy(s, 'Hello world', ALL)
  4417.             WriteF('The third element of s is "\c"\n', s[2])
  4418.             WriteF('or \d[4] (decimal)\n',             s[2])
  4419.             WriteF('or \z\h[4] (hexadecimal)\n',       s[2])
  4420.             WriteF('\a\s[5]\a are the first five elements of s \n', s)
  4421.             WriteF('and s in a very big field  \a\s[20]\a\n',   s)
  4422.             WriteF('and s left justified in it \a\l\s[20]\a\n', s)
  4423.           ENDPROC
  4424.  
  4425.      Here's the output it should generate:
  4426.  
  4427.           The third element of s is "l"
  4428.           or  108 (decimal)
  4429.           or 006C (hexadecimal)
  4430.           'Hello' are the first five elements of s
  4431.           and s in a very big field  '         Hello world'
  4432.           and s left justified in it 'Hello world         '
  4433.  
  4434.      WriteF uses the standard output, and this file handle is stored in
  4435.      the variables stdout and conout.  If your program is started from
  4436.      Workbench both variables will contain NIL.  In this case, the first
  4437.      call to WriteF will open a special output window and put the file
  4438.      handle in these variables.  Actually, WriteF checks whether stdout
  4439.      contains a file handle and uses that if it is not NIL, and the file
  4440.      handle in conout is the one that will be closed by E when the program
  4441.      finishes.  You can, therefore, open your own window and store the
  4442.      file handle in stdout so that all output goes to this window.  If
  4443.      conout was originally NIL you can put this file handle here, too, and
  4444.      E will close it for you when the program terminates.  Otherwise, you
  4445.      have to close the window yourself when you've finished with it.
  4446.  
  4447. StringF(e-string,string,arg1,arg2,...)
  4448.      The same as WriteF except that the result is written to e-string
  4449.      instead of being printed.  For example, the following code fragment
  4450.      sets s to 00123 is a (since the E-string is not long enough for the
  4451.      whole string):
  4452.  
  4453.             DEF s[10]:STRING
  4454.             StringF(s, '\z\d[5] is a number', 123)
  4455.  
  4456. Out(filehandle,char)
  4457.      Outputs a single character, char, to the file or console window
  4458.      denoted by filehandle.  For instance, filehandle could be stdout, in
  4459.      which case the character is written to the standard output.  (You
  4460.      need to make sure stdout is not NIL, and you can do this by using a
  4461.      WriteF('') call.)
  4462.  
  4463. Inp(filehandle)
  4464.      Reads and returns a single character from filehandle.  If -1 is
  4465.      returned then the end of the file (EOF) was reached, or there was an
  4466.      error.
  4467.  
  4468. ReadStr(filehandle,e-string)
  4469.      Reads a whole string from filehandle and returns -1 if EOF was
  4470.      reached or an error occurred.  Characters are read up to a linefeed
  4471.      or the size of the string, which ever is sooner.  Therefore, the
  4472.      resulting string may be only a partial line.  If -1 is returned then
  4473.      EOF was reached or an error occurred, and in either case the string
  4474.      so far is still valid.  So, you still need to check the string even
  4475.      if -1 is returned.  (This will most commonly happen with files that
  4476.      do not end with a linefeed.) The string will be empty (i.e., of zero
  4477.      length) if nothing more had been read from the file when the error or
  4478.      EOF happened.
  4479.  
  4480.      This next little program reads continually from the stdout window
  4481.      until an error occurs or the user types quit.  It echoes the lines
  4482.      that it reads in uppercase.  If you type a line longer than ten
  4483.      characters you'll see it reads it in more than one go.  Because of
  4484.      the way normal console windows work, you need to type a return before
  4485.      a line gets read by the program (but this allows you to edit the line
  4486.      before the porgram sees it).  Notice the use of WriteF('') to ensure
  4487.      that stdout is a console window, even if the program is started from
  4488.      Workbench.
  4489.  
  4490.           PROC main()
  4491.             DEF s[10]:STRING
  4492.             WriteF('')
  4493.             WHILE ReadStr(stdout, s)<>-1
  4494.               UpperStr(s)
  4495.               IF StrCmp(s, 'QUIT', ALL) THEN JUMP end
  4496.               WriteF('Read: \a\s\a\n', s)
  4497.             ENDWHILE
  4498.           end:
  4499.             WriteF('Finished\n')
  4500.           ENDPROC
  4501.  
  4502. FileLength(string)
  4503.      Returns the length of the file named in string, or -1 if the file
  4504.      doesn't exist or an error occurred.  Notice that you don't need to
  4505.      Open the file or have a filehandle, you just supply the filename.
  4506.  
  4507. SetStdOut(filehandle)
  4508.      Returns the value of stdout before setting it to filehandle.
  4509.      Therefore, the following code fragments are equivalent:
  4510.  
  4511.             oldstdout:=SetStdOut(newstdout)
  4512.           
  4513.             oldstdout:=stdout
  4514.             stdout:=newstdout
  4515.  
  4516. ========================================================================
  4517.  
  4518.  
  4519. Intuition support functions
  4520. ---------------------------
  4521.  
  4522.    The functions in this section are simplified versions of Amiga system
  4523. functions (in the Intuition library, as the title suggests).  To make best
  4524. use of them you are probably going to need something like the `Rom Kernel
  4525. Reference Manual (Libraries)', especially if you want to understand the
  4526. Amiga specific things like IDCMP and raster ports.
  4527.  
  4528.    The descriptions given here vary slightly in style from the previous
  4529. descriptions.  All function parameters can be expressions which represent
  4530. numbers or addresses, as appropriate.  Because many of the functions take
  4531. several parameters they have been named in (fairly descriptively) so they
  4532. can be more easily referenced.
  4533.  
  4534. OpenW(x,y,wid,hgt,idcmp,wflgs,title,scrn,sflgs,gads)
  4535.      Opens and returns a pointer to a window with the supplied properties.
  4536.      If for some reason the window could not be opened NIL is returned.
  4537.  
  4538.     x,  y
  4539.           The position on the screen where the window will appear.
  4540.  
  4541.     wid,  hgt
  4542.           The width and height of the window.
  4543.  
  4544.     idcmp,  wflgs
  4545.           The IDCMP and window specific flags.
  4546.  
  4547.     title
  4548.           The window title (a string) which appears on the title bar of
  4549.           the window.
  4550.  
  4551.     scrn,  sflgs
  4552.           The screen on which the window should open.  If sflgs is 1 the
  4553.           window will be opened on Workbench, and scrn is ignored (so it
  4554.           can be NIL).  If sflgs is $F (i.e., 15) the window will open on
  4555.           the custom screen pointed to by scrn (which must then be valid).
  4556.           See OpenS to see how to open a custom screen and get a screen
  4557.           pointer.
  4558.  
  4559.     gads
  4560.           A pointer to a gadget list, or NIL if you don't want any gadgets.
  4561.           These are not the standard window gadgets, since they are
  4562.           specified using  the window flags.  A gadget list can be created
  4563.           using the Gadget function.
  4564.  
  4565.      There's not enough space to describe all the fine details about
  4566.      windows and IDCMP (see the `Rom Kernel Reference Manual (Libraries)'
  4567.      for complete details), but a brief description in terms of flags
  4568.      might be useful.  Here's a small table of common IDCMP flags:
  4569.  
  4570.           IDCMP Flag           Value
  4571.           --------------------------
  4572.           IDCMP_NEWSIZE           $2
  4573.           IDCMP_MOUSEMOVE        $10
  4574.           IDCMP_GADGETDOWN       $20
  4575.           IDCMP_GADGETUP         $40
  4576.           IDCMP_MENUPICK        $100
  4577.           IDCMP_CLOSEWINDOW     $200
  4578.           IDCMP_RAWKEY          $400
  4579.           IDCMP_DISKINSERTED   $8000
  4580.           IDCMP_DISKREMOVED   $10000
  4581.  
  4582.      Here's a table of useful window flags:
  4583.  
  4584.           Window Flag          Value
  4585.           --------------------------
  4586.           WFLG_SIZEGADGET         $1
  4587.           WFLG_DRAGBAR            $2
  4588.           WFLG_DEPTHGADGET        $4
  4589.           WFLG_CLOSEGADGET        $8
  4590.           WFLG_SIZEBRIGHT        $10
  4591.           WFLG_SIZEBBOTTOM       $20
  4592.           WFLG_SMART_REFRESH       0
  4593.           WFLG_SIMPLE_REFRESH    $40
  4594.           WFLG_SUPER_BITMAP      $80
  4595.           WFLG_BACKDROP         $100
  4596.           WFLG_REPORTMOUSE      $200
  4597.           WFLG_GIMMEZEROZERO    $400
  4598.           WFLG_BORDERLESS       $800
  4599.           WFLG_ACTIVATE        $1000
  4600.  
  4601.      All these flags are defined in the module intuition/intuition, so if
  4602.      you use that module you can use the constants rather than having to
  4603.      write the less descriptive value (see Modules).  Of course, you can
  4604.      always define your own constants for the values that you use.
  4605.  
  4606.      You use the flags by OR-ing the ones you want together, in similar
  4607.      way to using sets (see Sets).  However, you should supply only IDCMP
  4608.      flags as part of the idcmp parameter, and you should supply only
  4609.      window flags as part of the wflgs parameter.  So, to get IDCMP
  4610.      messages when a disk is inserted and when the close gadget is clicked
  4611.      you specify both of the flags IDCMP_DISKINSERTED and
  4612.      IDCMP_CLOSEWINDOW for the idcmp parameter, either by OR-ing the
  4613.      constants or (less readably) by using the calculated value $8200.
  4614.  
  4615.      Some of the window flags require some of IDCMP flags to be used as
  4616.      well, if an effect is to be complete.  For example, if you want your
  4617.      window to have a close gadget (a standard window gadget) you need to
  4618.      use WFLG_CLOSEGADGET as one of the window flags.  If you want that
  4619.      gadget to be useful then you need to get an IDCMP message when the
  4620.      gadget is clicked.  You therefore need to use IDCMP_CLOSEWINDOW as
  4621.      one of the IDCMP flags.  So the full effect requires both a window
  4622.      and an IDCMP flag (a gadget is pretty useless if you can't tell when
  4623.      it's been clicked).  The worked example in Part Three illustrates how
  4624.      to use these flags in this way (see Gadgets).
  4625.  
  4626.      If you only want to output text to a window (and maybe do some input
  4627.      from a window), it may be better to use a console window.  These
  4628.      provide a text based input and output window, and are opened using
  4629.      the Dos library function Open with the appropriate CON: file name.
  4630.      See the `AmigaDOS Manual' for more details about console windows.
  4631.  
  4632. CloseW(winptr)
  4633.      Closes the window which is pointed to by winptr.  It's safe to give
  4634.      NIL for winptr, but in this case, of course, no window will be closed!
  4635.      The window pointer is usually a pointer returned by a matching call
  4636.      to OpenW.  You must remember to close any windows you may have opened
  4637.      before terminating your program.
  4638.  
  4639. OpenS(wid,hgt,depth,scrnres,title)
  4640.      Opens and returns a pointer to a custom screen with the supplied
  4641.      properties.  If for some reason the screen could not be opened NIL is
  4642.      returned.
  4643.  
  4644.     wid,  hgt
  4645.           The width and height of the screen.
  4646.  
  4647.     depth
  4648.           The depth of the screen, i.e., the number of bit-planes.  This
  4649.           can be a number in the range 1-8 for AGA machines, or 1-6 for
  4650.           pre-AGA machines.  A screen with depth 3 will be able to show 2
  4651.           to the power 3 (i.e., 8) different colours, since it will have 2
  4652.           to the power 3 different pens (or colour registers) available.
  4653.           You set the colours of pens using the Amiga system function
  4654.           SetRGB32 for AGA machines or SetRGB4 for pre-AGA machines.  See
  4655.           the `Rom Kernel Reference Manual (Libraries)' for more details.
  4656.  
  4657.     scrnres
  4658.           The screen resolution flags.
  4659.  
  4660.     title
  4661.           The screen title (a string) which appears on the title bar of
  4662.           the screen.
  4663.  
  4664.      The screen resolution flags control the screen mode.  The following
  4665.      (common) values are taken from the module graphics/view (see Modules).
  4666.      You can, if you want, define your own constants for the values that
  4667.      you use.  Either way it's best to use descriptive constants rather
  4668.      than directly using the values.
  4669.  
  4670.           Mode Flag          Value
  4671.           ------------------------
  4672.           V_LACE                $4
  4673.           V_SUPERHIRES         $20
  4674.           V_PFBA               $40
  4675.           V_EXTRA_HALFBRITE    $80
  4676.           V_DUALPF            $400
  4677.           V_HAM               $800
  4678.           V_HIRES            $8000
  4679.  
  4680.      So, to get a hires, interlaced screen you specify both of the flags
  4681.      V_HIRES and V_LACE, either by OR-ing the constants or (less readably)
  4682.      by using calculated value $8004.  There is a worked example using
  4683.      this function in Part Three (see Screens).
  4684.  
  4685. CloseS(scrnptr)
  4686.      Closes the screen which is pointed to by scrnptr.  It's safe to give
  4687.      NIL for scrnptr, but in this case, of course, no screen will be
  4688.      closed!  The screen pointer is usually a pointer returned by a
  4689.      matching call to OpenS.  You must remember to close any screens you
  4690.      may have opened before terminating your program.  Also, you must
  4691.      close all windows that you opened on your screen before you can close
  4692.      the screen.
  4693.  
  4694. Gadget(buf,glist,id,flags,x,y,width,text)
  4695.      Creates a new gadget with the supplied properties and returns a
  4696.      pointer to the next position in the (memory) buffer which can be used
  4697.      for a gadget.
  4698.  
  4699.     buf
  4700.           This is the memory buffer, i.e., a chunk of allocated memory.
  4701.           The best way of allocating this memory is to declare an array of
  4702.           size n*GADGETSIZE, where n is the number of gadgets which are
  4703.           going to be created.  The first call to Gadget will use the
  4704.           array as the buffer, and subsequent calls use the result of the
  4705.           previous call as the buffer (since this function returns the
  4706.           next free position in the buffer).
  4707.  
  4708.     glist
  4709.           This is a pointer to the gadget list that is being created,
  4710.           i.e., the array used as the buffer.  When you create the first
  4711.           gadget in the list using an array a, this parameter should be
  4712.           NIL.  For all other gadgets in the list this parameter
  4713.           should be the array a.
  4714.  
  4715.     id
  4716.           A number which identifies the gadget.  It is best to give a
  4717.           unique number for each gadget, that way you can easily identify
  4718.           them.  This number is the only way you can identify which gadget
  4719.           has been clicked.
  4720.  
  4721.     flags
  4722.           The type of gadget to be created.  Zero represents a normal
  4723.           gadget, one a boolean gadget (a toggle) and three a boolean that
  4724.           starts selected.
  4725.  
  4726.     x,  y
  4727.           The position of the gadget, relative to the top, left-hand
  4728.           corner of the window.
  4729.  
  4730.     width
  4731.           The width of the gadget (in pixels, not characters).
  4732.  
  4733.     text
  4734.           The text (a string) which will centred in the gadget, so the
  4735.           width must be big enough to hold this text.
  4736.  
  4737.      Once a gadget list has been created by possibly several calls to this
  4738.      function the list can be passed as the gads parameter to OpenW.
  4739.      There is a worked example using this function in Part Three (see
  4740.      Gadgets).
  4741.  
  4742. Mouse()
  4743.      Returns the state of the mouse buttons (including the middle mouse
  4744.      button if you have a three-button mouse).  This is a set of flags,
  4745.      and the individual flag values are:
  4746.  
  4747.           Button Pressed   Value
  4748.           ----------------------
  4749.           Left              %001
  4750.           Middle            %010
  4751.           Right             %100
  4752.  
  4753.      So, if this function returns %001 you know the left button is being
  4754.      pressed, and if it returns %110 you know the middle and right buttons
  4755.      are both being pressed.
  4756.  
  4757. MouseX(winptr)
  4758.      Returns the x coordinate of the mouse pointer, relative to the window
  4759.      pointed to by winptr.
  4760.  
  4761. MouseY(winptr)
  4762.      Returns the y coordinate of the mouse pointer, relative to the window
  4763.      pointed to by winptr.
  4764.  
  4765.      The three mouse functions are not strictly the proper way to do
  4766.      things.  It is suggested you use these functions only for small tests
  4767.      or demo-like programs.  The proper way of getting mouse details is to
  4768.      use the appropriate IDCMP flags for your window, wait for events and
  4769.      decode the information.
  4770.  
  4771. WaitIMessage(winptr)
  4772.      This function waits for a message from Intuition for the window
  4773.      pointed to by winptr and returns the class of the message (which is
  4774.      an IDCMP flag).  If you did not specify any IDCMP flags when the
  4775.      window was opened, or the specified messages could never happen
  4776.      (e.g., you asked only for gadget messages and you have no gadgets),
  4777.      then this function may wait forever.  When you've got a message you
  4778.      can use the MsgXXX functions to get some more information about the
  4779.      message.  See the `Rom Kernel Reference Manual (Libraries)' for more
  4780.      details on Intuition and IDCMP.  There is a worked example using this
  4781.      function in Part Three (see IDCMP Messages).
  4782.  
  4783.      This function is basically equivalent to the following function,
  4784.      except that the MsgXXX functions can also access the message data
  4785.      held in the variables code, qual and iaddr.
  4786.  
  4787.           PROC waitimessage(win:PTR TO window)
  4788.             DEF port,msg:PTR TO intuimessage,class,code,qual,iaddr
  4789.             port:=win.userport
  4790.             IF (msg:=GetMsg(port))=NIL
  4791.               REPEAT
  4792.                 WaitPort(port)
  4793.               UNTIL (msg:=GetMsg(port))<>NIL
  4794.             ENDIF
  4795.             class:=msg.class
  4796.             code:=msg.code
  4797.             qual:=msg.qualifier
  4798.             iaddr:=msg.iaddress
  4799.             ReplyMsg(msg)
  4800.           ENDPROC class
  4801.  
  4802. MsgCode()
  4803.      Returns the code part of the message returned by WaitIMessage.
  4804.  
  4805. MsgIaddr()
  4806.      Returns the iaddr part of the message returned by WaitIMessage.
  4807.      There is a worked example using this function in Part Three (see
  4808.      IDCMP Messages).
  4809.  
  4810. MsgQualifier()
  4811.      Returns the qual part of the message returned by WaitIMessage.
  4812.  
  4813. ========================================================================
  4814.  
  4815.  
  4816. Graphics functions
  4817. ------------------
  4818.  
  4819.    The functions in this section use the standard raster port, the address
  4820. of which is held in the variable stdrast.  Most of the time you don't need
  4821. to worry about this because the E functions which open windows and screens
  4822. set up this variable (see Intuition support functions).  So, by default,
  4823. these functions affect the last window or screen opened.  When you close a
  4824. window or screen, stdrast becomes NIL and calls to these functions have no
  4825. effect.  There is a worked example using these functions in Part Three
  4826. (see Graphics).
  4827.  
  4828.    The descriptions in this section follow the same style as the previous
  4829. section.
  4830.  
  4831. Plot(x,y,pen)
  4832.      Plots a single point (x,y) in the specified pen colour.  The position
  4833.      is relative to the top, left-hand corner of the window or screen that
  4834.      is the current raster port (normally the last screen or window to be
  4835.      opened).  The range of pen values available depend on the screen
  4836.      setup, but are at best 0-255 on AGA machines and 0-31 on pre-AGA
  4837.      machines.  As a guide, the background colour is usually pen zero, and
  4838.      the main foreground colour is pen one.  You set the colours of pens
  4839.      using the Amiga system function SetRGB32 for AGA machines or SetRGB4
  4840.      for pre-AGA machines.  See the `Rom Kernel Reference Manual
  4841.      (Libraries)' for more details.
  4842.  
  4843. Line(x1,y1,x2,y2,pen)
  4844.      Draws the line (x1,y1) to (x2,y2) in the specified pen colour.
  4845.  
  4846. Box(x1,y1,x2,y2,pen)
  4847.      Draws the (filled) box with vertices (x1,y1), (x2,y1), (x1,y2) and
  4848.      (x2,y2) in the specified pen colour.
  4849.  
  4850. Colour(fore-pen,back-pen)
  4851.      Sets the foreground and background pen colours.  As mentioned above,
  4852.      the background colour is normally pen zero and the main foreground is
  4853.      pen one.  You can change these defaults with this function.
  4854.  
  4855. TextF(x,y,format-string,arg1,arg2,...)
  4856.      This works just like WriteF except the resulting string is written
  4857.      starting at point (x,y).  Also, don't use any line-feed, carriage
  4858.      return, tab or escape characters in the string--they don't behave
  4859.      like they do in WriteF.
  4860.  
  4861. SetStdRast(newrast)
  4862.      Returns the value of stdrast before setting it to the new value.  The
  4863.      following code fragments are equivalent:
  4864.  
  4865.             oldstdrast:=SetStdRast(newstdrast)
  4866.           
  4867.             oldstdrast:=stdrast
  4868.             stdrast:=newstdrast
  4869.  
  4870. SetTopaz(size)
  4871.      Sets the text font for the current raster port to Topaz at the
  4872.      specified size.
  4873.  
  4874. ========================================================================
  4875.  
  4876.  
  4877. Maths and logic functions
  4878. -------------------------
  4879.  
  4880.    We've already seen the standard arithmetic operators.  The addition, +,
  4881. and subtraction, -, operators use full 32-bit integers, but, for
  4882. efficiency, multiplication, *, and division, /, use restricted values.
  4883. You can only use * to multiply 16-bit integers, and the result will be a
  4884. 32-bit integer.  Similarly, you can only use / to divide a 32-bit integer
  4885. by a 16-bit integer, and the result will be a 16-bit integer.  The
  4886. restrictions do not affect most calculations, but if you really need to
  4887. use all 32-bit integers (and you can cope with overflows etc.) you can use
  4888. the Mul and Div functions.  Mul(a,b) corresponds to a*b, and Div(a,b)
  4889. corresponds to a/b.
  4890.  
  4891.    We've also met the logic operators AND and OR, which we know are really
  4892. bit-wise operators.  You can also use the functions And and Or to do
  4893. exactly the same as AND and OR (respectively).  So, for instance, And(a,b)
  4894. is the same as a AND b.  The reason for these functions is because there
  4895. are Not and Eor (bit-wise) functions, too (and there aren't operators for
  4896. these).  Not(a) swaps one and zero bits, so, for instance, Not(TRUE) is
  4897. FALSE and Not(FALSE) is TRUE.  Eor(a,b) is the exclusive version of Or and
  4898. does almost the same, except that Eor(1,1) is 0 whereas Or(1,1) is 1 (and
  4899. this extends to all the bits).  So, basically, Eor tells you which bits
  4900. are different, or, logically, if the truth values are different.
  4901. Therefore, Eor(TRUE,TRUE) is FALSE and Eor(TRUE,FALSE) is TRUE.
  4902.  
  4903.    There's a collection of other functions related to maths, logic or
  4904. numbers in general:
  4905.  
  4906. Abs(expression)
  4907.      Returns the absolute value of expression.  The absolute value of a
  4908.      number is that number made positive if necessary.  So, Abs(9) is 9,
  4909.      and Abs(-9) is also 9.
  4910.  
  4911. Even(expression)
  4912.      Returns TRUE if expression represents an even number, and FALSE
  4913.      otherwise.  Obviously, a number is either odd or even!
  4914.  
  4915. Odd(expression)
  4916.      Returns TRUE if expression represents an odd number, and FALSE
  4917.      otherwise.
  4918.  
  4919. Mod(exp1,exp2)
  4920.      Returns the 16-bit remainder (or modulus) of the division of the
  4921.      32-bit exp1 by the 16-bit exp2.  For example, Mod(26,7) is 5 (since
  4922.      26=(7*3)+5).
  4923.  
  4924. Rnd(expression)
  4925.      Returns a random number in the range 0 to (n-1), where expression
  4926.      represents the value n.  These numbers are pseudo-random, so although
  4927.      you appear to get a random value from each call, the sequence of
  4928.      numbers you get will probably be the same each time you run your
  4929.      program.  Before you use Rnd for the first time in your program you
  4930.      should call it with a negative number.  This decides the starting
  4931.      point for the pseudo-random numbers.
  4932.  
  4933. RndQ(expression)
  4934.      Returns a random 32-bit value, based on the seed expression.  This
  4935.      function is quicker than Rnd, but returns values in the 32-bit range,
  4936.      not a specified range.  The seed value is used to select different
  4937.      sequences of pseudo-random numbers, and the first call to RndQ should
  4938.      use a large value for the seed.
  4939.  
  4940. Shl(exp1,exp2)
  4941.      Returns the value represented by exp1 shifted exp2 bits to the left.
  4942.      For example, Shl(%0001110,2) is %0111000 and Shl(%0001011,3) is
  4943.      %1011000.  Shifting a number one bit to the left is generally the
  4944.      same as multiplying it by two (although this isn't true when you
  4945.      shift large positive or large negative values).
  4946.  
  4947. Shr(exp1,exp2)
  4948.      Returns the value represented by exp1 shifted exp2 bits to the right.
  4949.      For example, Shr(%0001110,2) is %0000011 and Shr(%1011010,3) is
  4950.      %0001011.  Shifting a number one bit to the right is generally the
  4951.      same as dividing it by two.
  4952.  
  4953. Long(addr),  Int(addr),  Char(addr)
  4954.      Returns the LONG, INT or CHAR value at the address addr.  These
  4955.      functions should be used only when setting up a pointer and
  4956.      dereferencing it in the normal way would make your program cluttered
  4957.      and less readable.  Use of functions like these is often called
  4958.      peeking memory (especially in dialects of the BASIC language).
  4959.  
  4960. PutLong(addr,exp),  PutInt(addr,exp),  PutChar(addr,exp)
  4961.      Writes the LONG, INT or CHAR value represented by exp to the address
  4962.      addr.  Again, these functions should be used only when really
  4963.      necessary.  Use of functions like these is often called poking memory.
  4964.  
  4965. ========================================================================
  4966.  
  4967.  
  4968. System support functions
  4969. ------------------------
  4970.  
  4971. New(expression)
  4972.      Returns a pointer to a newly allocated chunk of memory, which is
  4973.      expression number of bytes.  If the memory could not be allocated NIL
  4974.      is returned.  The memory is initialised to zero in each byte, and
  4975.      taken from any available store (Fast or Chip memory, in that order of
  4976.      preference).  When you've finished with this memory you can use
  4977.      Dispose to free it for use elsewhere in your program.  You don't have
  4978.      to Dispose with memory you allocated with New because your program
  4979.      will automatically free it when it terminates.  This is not true for
  4980.      memory allocated using the normal Amiga system routines.
  4981.  
  4982. Dispose(address)
  4983.      Used to free memory allocated with New.
  4984.  
  4985. DisposeLink(complex)
  4986.      Used to free the memory allocated String (see String functions) and
  4987.      List (see List functions).  Again, you should rarely need to use this
  4988.      function because the memory is automatically freed when the program
  4989.      terminates.
  4990.  
  4991. CleanUp(expression)
  4992.      Terminates the program at this point, and does the normal things an E
  4993.      program does when it finishes.  The value denoted by expression is
  4994.      returned as the error code for the program.  It is the replacement
  4995.      for the AmigaDOS Exit routine which should never be used in an E
  4996.      program.  This is the only safe way of terminating a program, other
  4997.      than reaching the (logical) end of the main procedure (which is by
  4998.      far the most common way!).
  4999.  
  5000. CtrlC()
  5001.      Returns TRUE if control-C has been pressed since the last call, and
  5002.      FALSE otherwise.  This is only sensible for programs started from the
  5003.      Shell/CLI.
  5004.  
  5005. FreeStack()
  5006.      Returns the current amount of free stack space for the program.  Only
  5007.      complicated programs need worry about things like stack.  Recursion
  5008.      is the main thing that eats a lot of stack space.
  5009.  
  5010. KickVersion(expression)
  5011.      Returns TRUE if your Kickstart revision is at least that given by
  5012.      expression, and FALSE otherwise.  For instance, KickVersion(37)
  5013.      checks whether you're running with Kickstart version 37 or greater
  5014.      (i.e., AmigaDOS 2.04 and above).
  5015.  
  5016. ========================================================================
  5017.  
  5018.  
  5019. Modules
  5020. *******
  5021.  
  5022.    A module is the E equivalent of a C header file and an Assembly include
  5023. file.  It can contain various object and constant definitions, and also
  5024. library function offsets and library base variables.  This information is
  5025. necessary for the correct use of a library.
  5026.  
  5027. Next:
  5028.  
  5029.   Using Modules  
  5030.   Amiga System Modules  
  5031.   Non-Standard Modules  
  5032.   Example Module Use  
  5033.  
  5034. ========================================================================
  5035.  
  5036.  
  5037. Using Modules
  5038. =============
  5039.  
  5040.    To use the definitions in a particular module you use the MODULE
  5041. statement at the beginning of your program (before the first procedure
  5042. definition).  You follow the MODULE keyword by a comma-separated list of
  5043. strings, each of which is the filename (or path if necessary) of a module
  5044. without the .m extension (every module file ends with .m).  The filenames
  5045. (and paths) are all relative to the logical volume Emodules:, which is
  5046. set-up using an assign as described in the `Reference Manual'.  For
  5047. instance, the statement:
  5048.  
  5049.      MODULE 'fred', 'dir/barney'
  5050.  
  5051. will try to load the files Emodules:fred.m and Emodules:dir/barney.m.  If
  5052. it can't find these files or they aren't proper modules the E compiler
  5053. will complain.
  5054.  
  5055.    All the definitions in the modules included in this way are available
  5056. to every procedure in the program.  To see what a module contains you can
  5057. use the showmodule program that comes with the Amiga E distribution.
  5058.  
  5059. ========================================================================
  5060.  
  5061.  
  5062. Amiga System Modules
  5063. ====================
  5064.  
  5065.    Amiga E comes with the standard Amiga system include files as E modules.
  5066. The AmigaDOS 2.04 modules are supplied with E version 2.1, and the
  5067. AmigaDOS 3.0 modules are supplied with E version 3.0.  However, modules
  5068. are much more useful in E version 3.0 (see Code Modules).  If you want to
  5069. use any of the standard Amiga libraries properly you will need to
  5070. investigate the modules for that library.  The top-level .m files in
  5071. Emodules: contain the library function offsets, and those in directories
  5072. in Emodules: contain constant and object definitions for the appropriate
  5073. library.  For instance, the module asl (i.e., the file Emodules:asl.m)
  5074. contains the ASL library function offsets and libraries/asl contains the
  5075. ASL library constants and objects.
  5076.  
  5077.    If you are going to use, say, the ASL library then you need to open the
  5078. library using the OpenLibrary function (an Amiga system function) before
  5079. you can use any of the library functions.  You also need to define the
  5080. library function offsets by using the MODULE statement.  However, the DOS,
  5081. Exec, Graphics and Intuition libraries don't need to be opened and their
  5082. function offsets are built in to E. That's why you won't find, for
  5083. example, a dos.m file in Emodules:.  The constants and objects for these
  5084. libraries still need to be included via modules (they are not built in to
  5085. E).
  5086.  
  5087. ========================================================================
  5088.  
  5089.  
  5090. Non-Standard Modules
  5091. ====================
  5092.  
  5093.    Several non-standard library modules are also supplied with Amiga E. To
  5094. make your own modules you need the pragma2module and iconvert programs.
  5095. These convert standard format C header files and Assembly include files to
  5096. modules.  The C header file should contain pragmas for function offsets,
  5097. and the Assembly include file should contain constant and structure
  5098. definitions (the Assembly structures will be converted to objects).
  5099. However, unless you're trying to do really advanced things you probably
  5100. don't need to worry about any of this!
  5101.  
  5102. ========================================================================
  5103.  
  5104.  
  5105. Example Module Use
  5106. ==================
  5107.  
  5108.    The gadget example program in Part Three shows how to use constants
  5109. from the module intuition/intuition (see Gadgets), and the IDCMP example
  5110. program shows the object gadget from that module being used (see
  5111. IDCMP Messages).  The following program uses the modules for the Reqtools
  5112. library, which is not a standard Amiga system library but a commonly used
  5113. one, and the appropriate modules are supplied with Amiga E. To run this
  5114. program, you will, of course, need the reqtools.library in Libs:.
  5115.  
  5116.      MODULE 'reqtools'
  5117.      
  5118.      PROC main()
  5119.        DEF col
  5120.        IF (reqtoolsbase:=OpenLibrary('reqtools.library',37))<>NIL
  5121.          IF (col:=RtPaletteRequestA('Select a colour', 0,0))<>-1
  5122.            RtEZRequestA('You picked colour \d',
  5123.                         'I did|I can\at remember',0,[col],0)
  5124.          ENDIF
  5125.          CloseLibrary(reqtoolsbase)
  5126.        ELSE
  5127.          WriteF('Could not open reqtools.library, version 37+\n')
  5128.        ENDIF
  5129.      ENDPROC
  5130.  
  5131. The reqtoolsbase variable is the library base variable for the Reqtools
  5132. library.  This is defined in the module reqtools and you must store the
  5133. result of the OpenLibrary call in this variable if you are going to use
  5134. any of the functions from the Reqtools library.  (You can find out which
  5135. variable to use for other libraries by running the showmodule program on
  5136. the library module for the library.) The two functions the program uses
  5137. are RtPaletteRequestA and RtEZRequestA.  Without the inclusion of the
  5138. reqtools module and the setting up of the reqtoolsbase variable you would
  5139. not be able to use these functions.  In fact, if you didn't have the
  5140. MODULE line you wouldn't even be able to compile the program because
  5141. the compiler wouldn't know where the functions came from and would
  5142. complain bitterly.
  5143.  
  5144.    Notice that the Reqtools library is closed before the program
  5145. terminates (if it had been successfully opened).  This is always
  5146. necessary: if you succeed in opening a library you must close it when
  5147. you're finished with it.
  5148.  
  5149. ========================================================================
  5150.  
  5151.  
  5152. Exception Handling
  5153. ******************
  5154.  
  5155.    Often your program has to check the results of functions and do
  5156. different things if errors have occurred.  For instance, if you try to
  5157. open a window (using OpenW), you may get a NIL pointer returned which
  5158. shows that the window could not be opened for some reason.  In this case
  5159. you normally can't continue with the program, so you must tidy up and
  5160. terminate.  Tidying up can sometimes involve closing windows, screens and
  5161. libraries, so sometimes your error cases can make your program cluttered
  5162. and messy.  This is where exceptions come in--an exception is simply an
  5163. error case, and exception handling is dealing with error cases.  The
  5164. exception handling in E neatly separates error specific code from the real
  5165. code of your program.
  5166.  
  5167. Next:
  5168.  
  5169.   Procedures with Exception Handlers  
  5170.   Raising an Exception  
  5171.   Automatic Exceptions  
  5172.   Raise within an Exception Handler  
  5173.  
  5174. ========================================================================
  5175.  
  5176.  
  5177. Procedures with Exception Handlers
  5178. ==================================
  5179.  
  5180.    A procedure with an exception handler looks like this:
  5181.  
  5182.      PROC fred(params...) HANDLE
  5183.        /* Main, real code */
  5184.      EXCEPT
  5185.        /* Error handling code */
  5186.      ENDPROC
  5187.  
  5188. This is very similar to a normal procedure, apart from the HANDLE and
  5189. EXCEPT keywords.  The HANDLE keyword means the procedure is going to have
  5190. an exception handler, and the EXCEPT keyword marks the end of the normal
  5191. code and the start of the exception handling code.  The procedure works
  5192. just as normal, executing the code in the part before the EXCEPT, but when
  5193. an error happens you can pass control to the exception handler (i.e., the
  5194. code after the EXCEPT is executed).
  5195.  
  5196. ========================================================================
  5197.  
  5198.  
  5199. Raising an Exception
  5200. ====================
  5201.  
  5202.    When an error occurs (and you want to handle it), you raise an
  5203. exception using the Raise function.  You call this function with a number
  5204. which identifies the kind of error that occurred.  The code in the
  5205. exception handler is responsible for decoding the number and then doing
  5206. the appropriate thing.
  5207.  
  5208.    When Raise is called it immediately stops the execution of the current
  5209. procedure code and passes control to the exception handler of most recent
  5210. procedure which has a handler (which may be the current procedure).  This
  5211. is a bit complicated, but you can stick to raising exceptions and handling
  5212. them in the same procedure, as in the next example:
  5213.  
  5214.      CONST BIG_AMOUNT = 100000
  5215.      
  5216.      ENUM ERR_MEM
  5217.      
  5218.      PROC main() HANDLE
  5219.        DEF block
  5220.        block:=New(BIG_AMOUNT)
  5221.        IF block=NIL THEN Raise(ERR_MEM)
  5222.        WriteF('Got enough memory\n')
  5223.      EXCEPT
  5224.        IF exception=ERR_MEM
  5225.          WriteF('Not enough memory\n')
  5226.        ELSE
  5227.          WriteF('Unknown exception\n')
  5228.        ENDIF
  5229.      ENDPROC
  5230.  
  5231. This uses an exception handler to print a message saying there wasn't
  5232. enough memory if the call to New returns NIL.  The parameter to Raise is
  5233. stored in the special variable exception in the exception handler part of
  5234. the code, so if Raise is called with a number other than ERR_MEM a message
  5235. saying "Unknown exception" will be printed.
  5236.  
  5237.    Try running this program with a really large BIG_AMOUNT constant, so
  5238. that the New can't allocate the memory.  Notice that the "Got enough
  5239. memory" is not printed if Raise is called.  That's because the execution
  5240. of the normal procedure code stops when Raise is called, and control
  5241. passes to the appropriate exception handler.  When the end of the
  5242. exception handler is reached the procedure is finished, and in this case
  5243. the program terminates because the procedure was the main procedure.
  5244.  
  5245.    An enumeration (using ENUM) is a good way of getting different
  5246. constants for various exceptions.  It's always a good idea to use
  5247. constants for the parameter to Raise and in the exception handler, because
  5248. it makes everything a lot more readable: Raise(ERR_MEM) is much clearer
  5249. than Raise(0).
  5250.  
  5251.    So, what happens if you call Raise in a procedure without an exception
  5252. handler?  Well, this is where the real power of the handling mechanism
  5253. comes to light.  In this case, control passes to the exception handler of
  5254. the most recent procedure with a handler.  If none are found then the
  5255. program terminates.  Recent means one of the procedures involved in
  5256. calling your procedure.  So, if the procedure fred calls barney, then when
  5257. barney is being executed fred is a recent procedure.  Because the main
  5258. procedure is where the program starts it is a recent procedure for every
  5259. other procedure in the program.  This means, in practice:
  5260.  
  5261.    * If you define fred to be a procedure with an exception handler then
  5262.      any procedures called by fred will have their exceptions handled by
  5263.      the handler in fred if they don't have their own handler.
  5264.  
  5265.    * If you define main to be a procedure with an exception handler then
  5266.      any exceptions that are raised will always be dealt with by some
  5267.      exception handling code (i.e., the handler of main or some other
  5268.      procedure).
  5269.  
  5270.    Here's a more complicated example:
  5271.  
  5272.      ENUM FRED, BARNEY
  5273.      
  5274.      PROC main()
  5275.        WriteF('Hello from main\n')
  5276.        fred()
  5277.        barney()
  5278.        WriteF('Goodbye from main\n')
  5279.      ENDPROC
  5280.      
  5281.      PROC fred() HANDLE
  5282.        WriteF(' Hello from fred\n')
  5283.        Raise(FRED)
  5284.        WriteF(' Goodbye from fred\n')
  5285.      EXCEPT
  5286.        WriteF(' Handler fred: \d\n', exception)
  5287.      ENDPROC
  5288.      
  5289.      PROC barney()
  5290.        WriteF('  Hello from barney\n')
  5291.        Raise(BARNEY)
  5292.        WriteF('  Goodbye from barney\n')
  5293.      ENDPROC
  5294.  
  5295. When you run this program you get the following output:
  5296.  
  5297.      Hello from main
  5298.       Hello from fred
  5299.       Handler fred: 0
  5300.        Hello from barney
  5301.  
  5302. This is because the fred procedure is terminated by the Raise(FRED) call,
  5303. and the whole program is terminated by the Raise(BARNEY) call (since
  5304. barney and main do not have handlers).
  5305.  
  5306.    Now try this:
  5307.  
  5308.      ENUM FRED, BARNEY
  5309.      
  5310.      PROC main()
  5311.        WriteF('Hello from main\n')
  5312.        fred()
  5313.        WriteF('Goodbye from main\n')
  5314.      ENDPROC
  5315.      
  5316.      PROC fred() HANDLE
  5317.        WriteF(' Hello from fred\n')
  5318.        barney()
  5319.        Raise(FRED)
  5320.        WriteF(' Goodbye from fred\n')
  5321.      EXCEPT
  5322.        WriteF(' Handler fred: \d\n', exception)
  5323.      ENDPROC
  5324.      
  5325.      PROC barney()
  5326.        WriteF('  Hello from barney\n')
  5327.        Raise(BARNEY)
  5328.        WriteF('  Goodbye from barney\n')
  5329.      ENDPROC
  5330.  
  5331. When you run this you get the following output:
  5332.  
  5333.      Hello from main
  5334.       Hello from fred
  5335.        Hello from barney
  5336.       Handler fred: 1
  5337.      Goodbye from main
  5338.  
  5339. Now the fred procedure calls barney, so main and fred are recent
  5340. procedures when Raise(BARNEY) is executed, and therefore the fred
  5341. exception handler is called.  When this handler finishes the call to fred
  5342. in main is finished, so the main procedure is completed and we see the
  5343. `Goodbye' message.  In the previous program the Raise(BARNEY) call did not
  5344. get handled and the whole program terminated at that point.
  5345.  
  5346. ========================================================================
  5347.  
  5348.  
  5349. Automatic Exceptions
  5350. ====================
  5351.  
  5352.    In the previous section we saw any example of raising an exception when
  5353. a call to New returned NIL.  We can re-write this example to use automatic
  5354. exception raising:
  5355.  
  5356.      CONST BIG_AMOUNT = 100000
  5357.      
  5358.      ENUM ERR_MEM
  5359.      
  5360.      RAISE ERR_MEM IF New()=NIL
  5361.      
  5362.      PROC main() HANDLE
  5363.        DEF block
  5364.        block:=New(BIG_AMOUNT)
  5365.        WriteF('Got enough memory\n')
  5366.      EXCEPT
  5367.        IF exception=ERR_MEM
  5368.          WriteF('Not enough memory\n')
  5369.        ELSE
  5370.          WriteF('Unknown exception\n')
  5371.        ENDIF
  5372.      ENDPROC
  5373.  
  5374. The only difference is the removal of the IF which checked the value of
  5375. block, and the addition of a RAISE part.  This RAISE part means that
  5376. whenever the New function is called in the program, the exception ERR_MEM
  5377. will be raised if it returns NIL (i.e., the exception ERR_MEM is
  5378. automatically raised).  This unclutters the program by removing a lot of
  5379. error checking IF statements.
  5380.  
  5381.    The precise form of the RAISE part is:
  5382.  
  5383.      RAISE exception  IF function()  compare  value ,
  5384.            exception2 IF function2() compare2 value2 ,
  5385.            ...
  5386.  
  5387. The exception is a constant (or number) which represents the exception to
  5388. be raised, function is the E built-in or system function to be
  5389. automatically checked, value is the return value to be checked against,
  5390. and  compare is the method of checking (i.e., =, <>, <, <=, > or >=).
  5391. This mechanism only exists for built-in or library functions becuase they
  5392. would otherwise have no way of raising exceptions.  The procedures you
  5393. define yourself can, of course, use Raise to raise exceptions in a much
  5394. more flexible way.
  5395.  
  5396. ========================================================================
  5397.  
  5398.  
  5399. Raise within an Exception Handler
  5400. =================================
  5401.  
  5402.    If you call Raise within an exception handler then control passes to
  5403. the next most recent handler.  In this way you can write procedures which
  5404. have handlers that perform local tidying up.  By using Raise at the end of
  5405. the handler code you can invoke the next layer of tidying up.
  5406.  
  5407.    As an example we'll use the Amiga system functions AllocMem and FreeMem
  5408. which are like the built-in function New and Dispose, but the memory
  5409. allocated by AllocMem must be deallocated (using FreeMem) when it's
  5410. finished with, before the end of the program.
  5411.  
  5412.      CONST SMALL=100, BIG=123456789
  5413.      
  5414.      ENUM ERR_MEM
  5415.      
  5416.      RAISE ERR_MEM IF AllocMem()=NIL
  5417.      
  5418.      PROC main()
  5419.        allocate()
  5420.      ENDPROC
  5421.      
  5422.      PROC allocate() HANDLE
  5423.        DEF mem=NIL
  5424.        mem:=AllocMem(SMALL, 0)
  5425.        morealloc()
  5426.        FreeMem(mem, SMALL)
  5427.      EXCEPT
  5428.        IF mem THEN FreeMem(mem, SMALL)
  5429.        WriteF('Handler: deallocating "allocate" local memory\n')
  5430.      ENDPROC
  5431.      
  5432.      PROC morealloc() HANDLE
  5433.        DEF more=NIL, andmore=NIL
  5434.        more:=AllocMem(SMALL, 0)
  5435.        andmore:=AllocMem(BIG, 0)
  5436.        WriteF('Allocated all the memory!\n')
  5437.        FreeMem(andmore, BIG)
  5438.        FreeMem(more, SMALL)
  5439.      EXCEPT
  5440.        IF andmore THEN FreeMem(andmore, BIG)
  5441.        IF more THEN FreeMem(more, SMALL)
  5442.        WriteF('Handler: deallocating "morealloc" local memory\n')
  5443.        Raise(ERR_MEM)
  5444.      ENDPROC
  5445.  
  5446. The calls to AllocMem are automatically checked, and if NIL is returned
  5447. the exception ERR_MEM is raised.  The handler in the allocate procedure
  5448. checks to see if it needs to free the memory pointed to by mem, and the
  5449. handler in the morealloc checks andmore and more.  At the end of the
  5450. morealloc handler is the call Raise(ERR_MEM).  This passes control to the
  5451. exception handler of the allocate procedure, since allocate called
  5452. morealloc.
  5453.  
  5454.    There's a couple of subtle points to notice about this example.
  5455. Firstly, the memory variables are all initialised to NIL.  This is because
  5456. the automatic exception raising on AllocMem will result in the variables
  5457. not being assigned if the call returns NIL (i.e., the exception is raised
  5458. before the assignment takes place).  Of course, if AllocMem does not
  5459. return NIL the assignments work as normal.
  5460.  
  5461.    Secondly, the IF statements in the handlers check the memory pointer
  5462. variables do not contain NIL by using their values as truth values.  Since
  5463. NIL is actually zero, a non-NIL pointer will be non-zero, i.e., true in
  5464. the IF check.  This shorthand is often used, and so you should be aware of
  5465. it.
  5466.  
  5467.    There is an example, in Part Three, of how to use an exception handler
  5468. to make a program more readable (see Screens).
  5469.  
  5470. ========================================================================
  5471.  
  5472.  
  5473. Recursion
  5474. *********
  5475.  
  5476.    A recursive function is very much like a function which uses a loop.
  5477. Basically, a recursive function calls itself (usually after some
  5478. manipulation of data) rather than iterating a bit of code using a loop.
  5479. There are also recursive types, which are objects with elements which have
  5480. the object type (in E these would be pointers to objects).  We've already
  5481. seen a recursive type: linked lists, where each element in the list
  5482. contains a pointer to the next element (see Linked Lists).
  5483.  
  5484.    Recursive definitions are normally much more understandable than an
  5485. equivalent iterative definition, and it's usually easier to use recursive
  5486. functions to manipulate this data from a recursive type.  However,
  5487. recursion is by no means a simple topic.  Read on at your own peril!
  5488.  
  5489. Next:
  5490.  
  5491.   Factorial Example  
  5492.   Mutual Recursion  
  5493.   Binary Trees  
  5494.   Stack (and Crashing)  
  5495.   Stack and Exceptions  
  5496.  
  5497. ========================================================================
  5498.  
  5499.  
  5500. Factorial Example
  5501. =================
  5502.  
  5503.    The normal example for a recursive definition is the factorial
  5504. function, so let's not be different.  In school mathematics the symbol !
  5505. is used after a number to denote the factorial of that number (and only
  5506. positive integers have factorials).  n! is n-factorial, which is defined
  5507. as follows:
  5508.  
  5509.      n! = n * (n-1) * (n-2) * ... * 1     (for n >= 1)
  5510.  
  5511. So, 4! is 4*3*2*1, which is 24.  And, 5! is 5*4*3*2*1, which is 120.
  5512.  
  5513.    Here's the iterative definition of a factorial function (we'll Raise an
  5514. exception is the number is not positive, but you can safely leave this
  5515. check out if you are sure the function will be called only with positive
  5516. numbers):
  5517.  
  5518.      PROC fact_iter(n)
  5519.        DEF i, result=1
  5520.        IF n<=0 THEN Raise("FACT")
  5521.        FOR i:=1 TO n
  5522.          result:=result*i
  5523.        ENDFOR
  5524.      ENDPROC result
  5525.  
  5526. We've used a FOR loop to generate the numbers one to n (the parameter to
  5527. the fact_iter), and result holds the intermediate and final results.  The
  5528. final result is returned, so check that fact_iter(4) returns 24 and
  5529. fact_iter(5) returns 120 using a main procedure something like this:
  5530.  
  5531.      PROC main()
  5532.        WriteF('4! is \d\n5! is\d\n', fact_iter(4), fact_iter(5))
  5533.      ENDPROC
  5534.  
  5535.    If you're really observant you might have noticed that 5! is 5*4!, and,
  5536. in general, n! is n*(n-1)!.  This is our first glimpse of a recursive
  5537. definition--we can define the factorial function in terms of itself.  The
  5538. real definition of factorial is (the reason why this is the real
  5539. definition is because the `...' in the previous definition is not
  5540. sufficiently precise for a mathematical definition):
  5541.  
  5542.      1! = 1
  5543.      n! = n * (n-1)!    (for n > 1)
  5544.  
  5545. Notice that there are now two cases to consider.  The first case is called
  5546. the base case and gives an easily calculated value (i.e., no recursion is
  5547. used).  The second case is the recursive case and gives a definition in
  5548. terms of a number nearer the base case (i.e., (n-1) is nearer 1 than n,
  5549. for n>1).  The normal problem people get into when using recursion is they
  5550. forget the base case.  Without the base case the definition is meaningless.
  5551. Without a base case in a recursive program the machine is likely to crash!
  5552. (See Stack (and Crashing).)
  5553.  
  5554.    We can now define the recursive version of the fact_iter function
  5555. (again, we'll use a Raise if the number parameter is not positive):
  5556.  
  5557.      PROC fact_rec(n)
  5558.        IF n=1
  5559.          RETURN 1
  5560.        ELSEIF n>=2
  5561.          RETURN n*fact_rec(n-1)
  5562.        ELSE
  5563.          Raise("FACT")
  5564.        ENDIF
  5565.      ENDPROC
  5566.  
  5567. Notice how this looks just like the mathematical definition, and is nice
  5568. and compact.  We can even make a one-line function definition (if we omit
  5569. the check on the parameter being positive):
  5570.  
  5571.      PROC fact_rec2(n) RETURN IF n=1 THEN 1 ELSE n*fact_rec2(n-1)
  5572.  
  5573. You might be tempted to omit the base case and write something like this:
  5574.  
  5575.      /* Don't do this! */
  5576.      PROC fact_bad(n) RETURN n*fact_bad(n-1)
  5577.  
  5578. The problem is the recursion will never end.  The function fact_bad will
  5579. be called with every number from n to zero and then all the negative
  5580. integers.  A value will never be returned, and the machine will crash
  5581. after a while.  The precise reason why it will crash is given later (see
  5582. Stack (and Crashing)).
  5583.  
  5584. ========================================================================
  5585.  
  5586.  
  5587. Mutual Recursion
  5588. ================
  5589.  
  5590.    In the previous section we saw the function fact_rec which called
  5591. itself.  If you have two functions, fun1 and fun2, and fun1 calls fun2,
  5592. and fun2 calls fun1, then this pair of functions are mutually recursive.
  5593. This extends to any amount of functions linked in this way.
  5594.  
  5595.    This is a rather contrived example of a pair of mutually recursive
  5596. functions.
  5597.  
  5598.      PROC f(n)
  5599.        IF n=1
  5600.          RETURN 1
  5601.        ELSEIF n>=2
  5602.          RETURN n*g(n-1)
  5603.        ELSE
  5604.          Raise("F")
  5605.        ENDIF
  5606.      ENDPROC
  5607.      
  5608.      PROC g(n)
  5609.        IF n=1
  5610.          RETURN 2*1
  5611.        ELSEIF n>=2
  5612.          RETURN 2*n*f(n-1)
  5613.        ELSE
  5614.          Raise("G")
  5615.        ENDIF
  5616.      ENDPROC
  5617.  
  5618. Both functions are very similar to the fact_rec function, but g returns
  5619. double the normal values.  The overall effect is that every other value in
  5620. long version of the multiplication is doubled.  So, f(n) computes
  5621. n*(2*(n-1))*(n-2)*(2*(n-3))*...*2 which probably isn't all that
  5622. interesting.
  5623.  
  5624. ========================================================================
  5625.  
  5626.  
  5627. Binary Trees
  5628. ============
  5629.  
  5630.    This is an example of a recursive type and the effect it has on
  5631. functions which manipulate this type of data.  A binary tree is like a
  5632. linked list, but instead of each element containing only one link to
  5633. another element there are two links in each element of a binary tree
  5634. (which point to smaller trees called branches).  The first link points to
  5635. the left branch and the second points to the right branch.  Each element
  5636. of the tree is called a node and there are two kinds of special node: the
  5637. start point, called the root of the tree (like the head of a list), and
  5638. the nodes which do not have left or right branches (i.e., NIL pointers for
  5639. both links), called leaves.  Every node of the tree contains some kind of
  5640. data (just as the linked lists contained an E-string or E-list in each
  5641. element).  The following diagram illustrates a small tree.
  5642.  
  5643.                  +------+
  5644.                  | Root |
  5645.                  +--*---+
  5646.                    / \
  5647.              Left /   \ Right
  5648.                  /     \
  5649.          +------*       *------+
  5650.          | Node |       | Node |
  5651.          +--*---+       +--*---+
  5652.            /              / \
  5653.      Left /         Left /   \ Right
  5654.          /              /     \
  5655.      +--*---+     +----*-+   +-*----+
  5656.      | Leaf |     | Leaf |   | Leaf |
  5657.      +------+     +------+   +------+
  5658.  
  5659. Notice that a node might have only one branch (it doesn't have to have
  5660. both the left and the right).  Also, the leaves on the example were all at
  5661. the same level, but this doesn't have to be the case.  Any of the leaves
  5662. could easily have been a node which had a lot of nodes branching off it.
  5663.  
  5664.    So, how can a tree structure like this be written as an E object?
  5665. Well, the general outline is this:
  5666.  
  5667.      OBJECT tree
  5668.        data
  5669.        left, right
  5670.      ENDOBJECT
  5671.  
  5672. The left and right elements are LONG values, so can be used to store
  5673. pointers to the left and right branches (which will be tree objects, too).
  5674. The data element is some data for each node.  This could equally well be a
  5675. pointer, an ARRAY or a number of different data elements.
  5676.  
  5677.    So, what use can be made of such a tree?  Well, a common use is for
  5678. holding a sorted collection of data that needs to be able to have elements
  5679. added quickly.  As an example, the data at each node could be an integer,
  5680. so a tree of this kind could hold a sorted set of integers.  To make the
  5681. tree sorted, constraints must be placed on the left and right branches of
  5682. a node.  The left branch should contain only nodes with data that is less
  5683. than the parent node's data, and, similarly, the right branch should
  5684. contain only nodes with data that is greater.  Nodes with the same data
  5685. could be included in one of the branches, but for our example we'll
  5686. disallow them.  We are now ready to write some functions to manipulate our
  5687. tree.
  5688.  
  5689.    The first function is one which starts off a new set of integers (i.e.,
  5690. begins a new tree).  This should take an integer as a parameter and return
  5691. a pointer to the root node of new tree (with the integer as that node's
  5692. data).
  5693.  
  5694.      PROC new_set(int)
  5695.        DEF root:PTR TO tree
  5696.        IF (root:=New(SIZEOF tree))=NIL
  5697.          Raise("RMEM")
  5698.        ELSE
  5699.          root.data:=int
  5700.        ENDIF
  5701.      ENDPROC root
  5702.  
  5703. The memory for the new tree element must be allocated dynamically using
  5704. New.  Since New clears the memory it allocates all elements of the new
  5705. object will be zero.  In particular, the left and right pointers will be
  5706. NIL, so the root node will also be a leaf.  If the New fails an exception
  5707. is raised; otherwise the data is set to the supplied value and a pointer
  5708. to the root node is returned.
  5709.  
  5710.    To add a new integer to such a set we need to find the appropriate
  5711. position to insert it and set the left and right branches correctly.  This
  5712. is because if the integer is new to the set it will be added as a new
  5713. leaf, and so one of the existing nodes will change its left or right
  5714. branch.
  5715.  
  5716.      PROC add(i, set:PTR TO tree)
  5717.        IF set=NIL
  5718.          RETURN new_set(i)
  5719.        ELSE
  5720.          IF i<set.data
  5721.            set.left:=add(i, set.left)
  5722.          ELSEIF i>set.data
  5723.            set.right:=add(i, set.right)
  5724.          ENDIF
  5725.          RETURN set
  5726.        ENDIF
  5727.      ENDPROC
  5728.  
  5729. This function returns a pointer to the set to which it added the integer.
  5730. If this set was initially empty a new set is created; otherwise the
  5731. original pointer is returned.  The appropriate branches are corrected as
  5732. the search progresses.  Only the last assignment to the left or right
  5733. branch is significant (all others do not change the value of the pointer),
  5734. since it is this assignment that adds the new leaf.  Here's an iterative
  5735. version of this function:
  5736.  
  5737.      PROC add_iter(i, set:PTR TO tree)
  5738.        DEF node:PTR TO tree
  5739.        IF set=NIL
  5740.          RETURN new_set(i)
  5741.        ELSE
  5742.          node:=set
  5743.          LOOP
  5744.            IF i<node.data
  5745.              IF node.left=NIL
  5746.                node.left:=new_set(i)
  5747.                RETURN set
  5748.              ELSE
  5749.                node:=node.left
  5750.              ENDIF
  5751.            ELSEIF i>node.data
  5752.              IF node.right=NIL
  5753.                node.right:=new_set(i)
  5754.                RETURN set
  5755.              ELSE
  5756.                node:=node.right
  5757.              ENDIF
  5758.            ELSE
  5759.              RETURN set
  5760.            ENDIF
  5761.          ENDLOOP
  5762.        ENDIF
  5763.      ENDPROC
  5764.  
  5765. As you can see, it's quite a bit messier.  Recursive functions work well
  5766. with manipulation of recursive types.
  5767.  
  5768.    Another really neat example is printing the contents of the set.  It's
  5769. deceptively simple:
  5770.  
  5771.      PROC show(set:PTR TO tree)
  5772.        IF set<>NIL
  5773.          show(set.left)
  5774.          WriteF('\d ', set.data)
  5775.          show(set.right)
  5776.        ENDIF
  5777.      ENDPROC
  5778.  
  5779. The integers in the nodes will get printed in order (providing they were
  5780. added using the add function).  The left-hand nodes contain the smallest
  5781. elements so the data they contain is printed first, followed by the data
  5782. at the current node, and then that in the right-hand nodes.  Try writing
  5783. an iterative version of this function if you fancy a really tough problem.
  5784.  
  5785.    Putting everything together, here's a main procedure which can be used
  5786. to test the above functions:
  5787.  
  5788.      PROC main()
  5789.        DEF s, i, j
  5790.        Rnd(-999999)    /* Initialise seed */
  5791.        s:=new_set(10)  /* Initialise set s to contain the number 10 */
  5792.        WriteF('Input:\n')
  5793.        FOR i:=1 TO 50  /* Generate 50 random numbers and add them to set s */
  5794.          j:=Rnd(100)
  5795.          add(j, s)
  5796.          WriteF('\d ',j)
  5797.        ENDFOR
  5798.        WriteF('\nOutput:\n')
  5799.        show(s)         /* Show the contents of the (sorted) set s */
  5800.        WriteF('\n')
  5801.      ENDPROC
  5802.  
  5803. ========================================================================
  5804.  
  5805.  
  5806. Stack (and Crashing)
  5807. ====================
  5808.  
  5809.    When you call a procedure you use up a bit of the program's stack.  The
  5810. stack is used to keep track of procedures in a program which haven't
  5811. finished, and real problems can arise when the stack space runs out.
  5812. Normally, the amount of stack available to each program is sufficient,
  5813. since the E compiler handles all the fiddly bits quite well.  However,
  5814. programs which use a lot of recursion can quite easily run out of stack.
  5815.  
  5816.    For example, the fact_rec(10) will need enough stack for ten calls of
  5817. fact_rec, nine of which are recursively called.  This is because each call
  5818. does not finish until the return value has been computed, so all recursive
  5819. calls up to fact_rec(1) need to be kept on the stack until fact_rec(1)
  5820. returns one.  Then each procedure will be taken off the stack as they
  5821. finish.  If you try to compute fact_rec(40000), not only will this take a
  5822. long time, but it will probably run out of stack space.  When it does run
  5823. out of stack, the machine will probably crash or do other weird things.
  5824. The iterative version, fact_iter does not have these problems, since it
  5825. only takes one procedure call to calculate a factorial using this function.
  5826.  
  5827.    If there is the possibility of running out of stack space you can use
  5828. the FreeStack (built-in) function call (see System support functions).
  5829. This returns the amount of free stack space.  If it drops below about 1KB
  5830. then you might like to stop the recursion or whatever else is using up the
  5831. stack.  Also, you can specify amount of stack your program gets (and
  5832. override what the compiler might decide is appropriate) using the OPT
  5833. STACK option.  See the `Reference Manual' for more details on E's
  5834. stack organisation.
  5835.  
  5836. ========================================================================
  5837.  
  5838.  
  5839. Stack and Exceptions
  5840. ====================
  5841.  
  5842.    The concept `recent' used earlier is connected with the stack (see
  5843. Raising an Exception).  A recent procedure is one which is on the stack,
  5844. the most recent being the current procedure.  So, when Raise is called it
  5845. looks through the stack until it finds a procedure with an exception
  5846. handler.  That handler will then be used, and all procedures before the
  5847. selected one on the stack are taken off the stack.
  5848.  
  5849.    Therefore, a recursive function with an exception handler can use Raise
  5850. in the handler to call the handler in the previous (recursive) call of the
  5851. function.  So anything that has been recursively allocated can be
  5852. `recursively' deallocated by exception handlers.  This is a very powerful
  5853. and important feature of exception handlers.
  5854.  
  5855. ========================================================================
  5856.  
  5857.  
  5858. Introduction to the Examples
  5859. ****************************
  5860.  
  5861.    In this part we shall go through some slightly larger examples than
  5862. those in the previous parts.  However, none of them are too big, so they
  5863. should still be easy to understand.  The note-worthy parts of each example
  5864. are described, and you may even find the odd comment in the code.  Large,
  5865. complicated programs benefit hugely from the odd well-placed and
  5866. descriptive comment.  This fact can't be stressed enough.
  5867.  
  5868.    Almost all the examples should run on a standard Amiga.  The timing
  5869. example will give better results on an A4000/040, though, and AmigaDOS 2.0
  5870. (and above) is really worth getting for the new, friendly system functions.
  5871. The ReadArgs example can only hint at the power of the newer system
  5872. functions.
  5873.  
  5874. ========================================================================
  5875.  
  5876.  
  5877. Timing Expressions
  5878. ******************
  5879.  
  5880.    You may recall the outline of a timing procedure in Part Two (see
  5881. Evaluation).  This chapter gives the complete version of this example.
  5882. The information missing from the outline was how to determine the system
  5883. time and use this to calculate the time taken by calls to Eval.  So the
  5884. things to notice about this example are:
  5885.  
  5886.    * Use of the Amiga system function DateStamp (from dos.library).  (You
  5887.      really need the `Rom Kernel Reference Manuals' and the `AmigaDOS
  5888.      Manual' to understand the system functions.)
  5889.  
  5890.    * Use of the module dos/dos to include the definitions of the object
  5891.      datestamp and the constant TICKS_PER_SECOND.  (There are fifty ticks
  5892.      per second.)
  5893.  
  5894.    * Use of the repeat procedure to do Eval a decent number of times for
  5895.      each expression (so that some time is taken up by the calls!).
  5896.  
  5897.    * The timing of the evaluation of 0, to calculate the overhead of the
  5898.      procedure calls and loop.  This value is stored in the variable
  5899.      offset the first time the test procedure is called.  The
  5900.      expression 0 should take a negligible amount of time, so the number
  5901.      of ticks timed is actually the time taken by the procedure calls and
  5902.      loop calculations.  Subtracting this time from the other times gives
  5903.      a fair view of how long the expressions take, relative to one another.
  5904.      (Thanks to Wouter for this offset idea.)
  5905.  
  5906.    * Use of Forbid and Permit to turn off multi-tasking temporarily,
  5907.      making the CPU calculate only the expressions (rather than dealing
  5908.      with screen output, other programs, etc.).
  5909.  
  5910.    * Use of CtrlC and CleanUp to allow the user to stop the program if it
  5911.      gets too boring...
  5912.  
  5913.    Also supplied are some example outputs.  The first was from an A1200
  5914. with 2MB Chip RAM and 4MB Fast RAM.  The second was from an A500Plus with
  5915. 2MB Chip RAM.  Both used the constant LOTS_OF_TIMES as 500,000, but you
  5916. might need to increase this number to compare, for instance, an A4000/040
  5917. to an A4000/030.  However, 500,000 gives a pretty long wait for results on
  5918. the A500.
  5919.  
  5920.      MODULE 'dos/dos'
  5921.      
  5922.      CONST TICKS_PER_MINUTE=TICKS_PER_SECOND*60, LOTS_OF_TIMES=500000
  5923.      
  5924.      DEF x, y, offset
  5925.      
  5926.      PROC main()
  5927.        x:=9999
  5928.        y:=1717
  5929.        test(`x+y,     'Addition')
  5930.        test(`y-x,     'Subtraction')
  5931.        test(`x*y,     'Multiplication')
  5932.        test(`x/y,     'Division')
  5933.        test(`x OR y,  'Bitwise OR')
  5934.        test(`x AND y, 'Bitwise AND')
  5935.        test(`x=y,     'Equality')
  5936.        test(`x<y,     'Less than')
  5937.        test(`x<=y,    'Less than or equal')
  5938.        test(`y:=1,    'Assignment of 1')
  5939.        test(`y:=x,    'Assignment of x')
  5940.        test(`y++,     'Increment')
  5941.        test(`IF FALSE THEN y ELSE x, 'IF FALSE')
  5942.        test(`IF TRUE THEN y ELSE x,  'IF TRUE')
  5943.        test(`IF x THEN y ELSE x,     'IF x')
  5944.        test(`fred(2),  'fred(2)')
  5945.      ENDPROC
  5946.      
  5947.      PROC fred(n)
  5948.        DEF i
  5949.        i:=n+x
  5950.      ENDPROC
  5951.      
  5952.      /* Repeat evaluation of an expression */
  5953.      PROC repeat(exp)
  5954.        DEF i
  5955.        FOR i:=0 TO LOTS_OF_TIMES
  5956.          Eval(exp)  /* Evaluate the expresssion */
  5957.        ENDFOR
  5958.      ENDPROC
  5959.      
  5960.      /* Time an expression, and set-up offset if not done already */
  5961.      PROC test(exp, message)
  5962.        DEF t
  5963.        IF offset=0 THEN offset:=time(`0)  /* Calculate offset */
  5964.        t:=time(exp)
  5965.        WriteF('\s:\t\d ticks\n', message, t-offset)
  5966.      ENDPROC
  5967.      
  5968.      /* Time the repeated calls, and calculate number of ticks */
  5969.      PROC time(x)
  5970.        DEF ds1:datestamp, ds2:datestamp
  5971.        Forbid()
  5972.        DateStamp(ds1)
  5973.        repeat(x)
  5974.        DateStamp(ds2)
  5975.        Permit()
  5976.        IF CtrlC() THEN CleanUp(1)
  5977.      ENDPROC ((ds2.minute-ds1.minute)*TICKS_PER_MINUTE)+ds2.tick-ds1.tick
  5978.  
  5979. Here's the output from the A1200:
  5980.  
  5981.      Addition:       21 ticks
  5982.      Subtraction:    22 ticks
  5983.      Multiplication: 64 ticks
  5984.      Division:       131 ticks
  5985.      Bitwise OR:     21 ticks
  5986.      Bitwise AND:    21 ticks
  5987.      Equality:       43 ticks
  5988.      Less than:      43 ticks
  5989.      Less than or equal:     66 ticks
  5990.      Assignment of 1:        7 ticks
  5991.      Assignment of x:        18 ticks
  5992.      Increment:      23 ticks
  5993.      IF FALSE:       39 ticks
  5994.      IF TRUE:        38 ticks
  5995.      IF x:   43 ticks
  5996.      fred(2):        96 ticks
  5997.  
  5998. Compare this to the output from the A500Plus:
  5999.  
  6000.      Addition:       116 ticks
  6001.      Subtraction:    115 ticks
  6002.      Multiplication: 293 ticks
  6003.      Division:       633 ticks
  6004.      Bitwise OR:     116 ticks
  6005.      Bitwise AND:    116 ticks
  6006.      Equality:       160 ticks
  6007.      Less than:      160 ticks
  6008.      Less than or equal:     160 ticks
  6009.      Assignment of 1:        60 ticks
  6010.      Assignment of x:        102 ticks
  6011.      Increment:      133 ticks
  6012.      IF FALSE:       116 ticks
  6013.      IF TRUE:        160 ticks
  6014.      IF x:           189 ticks
  6015.      fred(2):        511 ticks
  6016.  
  6017. Evidence, if it were needed, that the A1200 is roughly five times faster
  6018. than an A500, and that's not using the special 68020 CPU instructions!
  6019.  
  6020. ========================================================================
  6021.  
  6022.  
  6023. Argument Parsing
  6024. ****************
  6025.  
  6026.    There are two examples in this chapter.  One is for any AmigaDOS and
  6027. the other is for AmigaDOS 2.0 and above.  They both illustrate how to
  6028. parse the arguments to your program.  If your program is started from the
  6029. Shell/CLI the arguments follow the command name on the command line, but
  6030. if it was started from Workbench (i.e., you double-clicked on an icon for
  6031. the program) then the arguments are those icons that were also selected at
  6032. that time (see your Workbench manual for more details).
  6033.  
  6034. Next:
  6035.  
  6036.   Any AmigaDOS  
  6037.   AmigaDOS 2.0 (and above)  
  6038.  
  6039. ========================================================================
  6040.  
  6041.  
  6042. Any AmigaDOS
  6043. ============
  6044.  
  6045.    This first example works with any AmigaDOS.  The first thing that is
  6046. done is the assignment of wbmessage to a correctly typed pointer.  At the
  6047. same time we can check to see if it is NIL (i.e., whether the program was
  6048. started from Workbench or not).  If it was not started from Workbench the
  6049. arguments in arg are printed.  Otherwise we need to use the fact that
  6050. wbmessage is really a pointer to a wbstartup object (defined in module
  6051. workbench/startup), so we can get at the argument list.  Then for each
  6052. argument in the list we need to check the lock supplied with the argument.
  6053. If it's a proper lock it will be a lock on the directory containing the
  6054. argument file.  The name in the argument is just a filename, not a
  6055. complete path, so to read the file we need to change the current directory
  6056. to the lock directory.  Once we've got a valid lock and we've changed
  6057. directory to there, we can find the length of the file (using FileLength)
  6058. and print it.  If there was no lock or the file did not exist, the name of
  6059. the file and an appropriate error message is printed.
  6060.  
  6061.      MODULE 'workbench/startup'
  6062.      
  6063.      PROC main()
  6064.        DEF startup:PTR TO wbstartup, args:PTR TO wbarg, i, oldlock, len
  6065.        IF (startup:=wbmessage)=NIL
  6066.          WriteF('Started from Shell/CLI\n   Arguments: "\s"\n', arg)
  6067.        ELSE
  6068.          WriteF('Started from Workbench\n')
  6069.          args:=startup.arglist
  6070.          FOR i:=1 to startup.numargs  /* Loop through the arguments */
  6071.            IF args[].lock=NIL
  6072.              WriteF('  Argument \d: "\s" (no lock)\n', i, args[].name)
  6073.            ELSE
  6074.              oldlock:=CurrentDir(args[].lock)
  6075.              len:=FileLength(args[].name)  /* Do something with file */
  6076.              IF len=-1
  6077.                WriteF('  Argument \d: "\s" (file does not exist)\n',
  6078.                       i, args[].name)
  6079.              ELSE
  6080.                WriteF('  Argument \d: "\s", file length is \d bytes\n',
  6081.                       i, args[].name, len)
  6082.              ENDIF
  6083.              CurrentDir(oldlock) /* Important: restore current dir */
  6084.            ENDIF
  6085.            args++
  6086.          ENDFOR
  6087.        ENDIF
  6088.      ENDPROC
  6089.  
  6090. When you run this program you'll notice a slight difference between arg
  6091. and the Workbench message: arg does not contain the program name, just the
  6092. arguments, whereas the first argument in the Workbench argument list is
  6093. the program.  You can simply ignore the first Workbench argument in the
  6094. list if you want.
  6095.  
  6096. ========================================================================
  6097.  
  6098.  
  6099. AmigaDOS 2.0 (and above)
  6100. ========================
  6101.  
  6102.    This second program can be used as the Shell/CLI part of the previous
  6103. program to provide much better command line parsing.  It can only be used
  6104. with AmigaDOS 2.0 and above (i.e., OSVERSION which is 37 or more).  The
  6105. template FILE/M used with ReadArgs gives command line parsing similar to
  6106. C's argv array.  The template can be much more interesting than this, but
  6107. for more details you need the `AmigaDOS Manual'.
  6108.  
  6109.      OPT OSVERSION=37
  6110.      
  6111.      PROC main()
  6112.        DEF templ, rdargs, args=NIL:PTR TO LONG, i
  6113.        IF wbmessage=NIL
  6114.          WriteF('Started from Shell/CLI\n')
  6115.          templ:='FILE/M'
  6116.          rdargs:=ReadArgs(templ,{args},NIL)
  6117.          IF rdargs
  6118.            IF args
  6119.              i:=0
  6120.              WHILE args[i]  /* Loop through arguments */
  6121.                WriteF('   Argument \d: "\s"\n', i, args[i])
  6122.                i++
  6123.              ENDWHILE
  6124.            ENDIF
  6125.            FreeArgs(rdargs)
  6126.          ENDIF
  6127.        ENDIF
  6128.      ENDPROC
  6129.  
  6130. As you can see the result of the ReadArgs call with this template is an
  6131. array of filenames.  The special quoting of filenames is dealt with
  6132. correctly (i.e., when you use " around a filename that contains spaces).
  6133. You need to do all this kind of work yourself if you use the arg method.
  6134.  
  6135. ========================================================================
  6136.  
  6137.  
  6138. Gadgets, IDCMP and Graphics
  6139. ***************************
  6140.  
  6141.    There are three examples in this chapter.  The first shows how to open
  6142. a window and put some gadgets on it.  The second shows how to decipher
  6143. Intuition messages that arrive via IDCMP.  The third draws things with the
  6144. graphics functions.
  6145.  
  6146. Next:
  6147.  
  6148.   Gadgets  
  6149.   IDCMP Messages  
  6150.   Graphics  
  6151.   Screens  
  6152.  
  6153. ========================================================================
  6154.  
  6155.  
  6156. Gadgets
  6157. =======
  6158.  
  6159.    The following program illustrates how to create a gadget list and use
  6160. it:
  6161.  
  6162.      MODULE 'intuition/intuition'
  6163.      
  6164.      CONST GADGETBUFSIZE = 4 * GADGETSIZE
  6165.      
  6166.      PROC main()
  6167.        DEF buf[GADGETBUFSIZE]:ARRAY, next, wptr
  6168.        next:=Gadget(buf,  NIL, 1, 0, 10, 30, 50, 'Hello')
  6169.        next:=Gadget(next, buf, 2, 3, 70, 30, 50, 'World')
  6170.        next:=Gadget(next, buf, 3, 1, 10, 50, 50, 'from')
  6171.        next:=Gadget(next, buf, 4, 0, 70, 50, 70, 'gadgets')
  6172.        wptr:=OpenW(20,50,200,100, 0, WFLG_ACTIVATE,
  6173.                    'Gadgets in a window',NIL,1,buf)
  6174.        IF wptr         /* Check to see we opened a window */
  6175.          Delay(500)    /* Wait a bit */
  6176.          CloseW(wptr)  /* Close the window */
  6177.        ELSE
  6178.          WriteF('Error -- could not open window!')
  6179.        ENDIF
  6180.      ENDPROC
  6181.  
  6182. Four gadgets are created using an appropriately sized array as the buffer.
  6183. These gadgets are passed to OpenW (the last parameter).  If the window
  6184. could be opened a small delay is used so that the window is visible before
  6185. the program closes it and terminates.  Delay is an Amiga system function
  6186. from the DOS library, and Delay(n) waits n/50 seconds.  Therefore, the
  6187. window stays up for 10 seconds, which is enough time to play with the
  6188. gadgets and see what the different types are.  The next example will show
  6189. a better way of deciding when to terminate the program (using the standard
  6190. close gadget).
  6191.  
  6192. ========================================================================
  6193.  
  6194.  
  6195. IDCMP Messages
  6196. ==============
  6197.  
  6198.    This next program shows how to use WaitIMessage with a gadget.
  6199.  
  6200.      MODULE 'intuition/intuition'
  6201.      
  6202.      CONST GADGETBUFSIZE = GADGETSIZE, OURGADGET = 1
  6203.      
  6204.      PROC main()
  6205.        DEF buf[GADGETBUFSIZE]:ARRAY, wptr, class, gad:PTR TO gadget
  6206.        Gadget(buf, NIL, OURGADGET, 1, 10, 30, 100, 'Press Me')
  6207.        wptr:=OpenW(20,50,200,100,
  6208.                    IDCMP_CLOSEWINDOW OR IDCMP_GADGETUP,
  6209.                    WFLG_CLOSEGADGET OR WFLG_ACTIVATE,
  6210.                    'Gadget message window',NIL,1,buf)
  6211.        IF wptr              /* Check to see we opened a window */
  6212.          WHILE (class:=WaitIMessage(wptr))<>IDCMP_CLOSEWINDOW
  6213.            gad:=MsgIaddr()  /* Our gadget clicked? */
  6214.            IF (class=IDCMP_GADGETUP) AND (gad.userdata=OURGADGET)
  6215.              TextF(10,60,
  6216.                    IF gad.flags=0 THEN 'Gadget off ' ELSE 'Gadget on   ')
  6217.            ENDIF
  6218.          ENDWHILE
  6219.          CloseW(wptr)       /* Close the window */
  6220.        ELSE
  6221.          WriteF('Error -- could not open window!')
  6222.        ENDIF
  6223.      ENDPROC
  6224.  
  6225. The gadget reports its state when you click on it, using the TextF
  6226. function (see Graphics functions).  The only way to quit the program is
  6227. using the close gadget of the window.  The gadget object is defined in the
  6228. module intuition/intuition and the iaddr part of the IDCMP message is a
  6229. pointer to our gadget if the message was a gadget message.  The userdata
  6230. element of the gadget identifies the gadget that was clicked, and the
  6231. flags element is zero if the boolean gadget is off (unselected) or
  6232. non-zero if the boolean gadget is on (selected).
  6233.  
  6234. ========================================================================
  6235.  
  6236.  
  6237. Graphics
  6238. ========
  6239.  
  6240.    The following program illustrates how to use the various graphics
  6241. functions.
  6242.  
  6243.      MODULE 'intuition/intuition'
  6244.      
  6245.      PROC main()
  6246.        DEF wptr, i
  6247.        wptr:=OpenW(20,50,200,100,IDCMP_CLOSEWINDOW,
  6248.                    WFLG_CLOSEGADGET OR WFLG_ACTIVATE,
  6249.                    'Graphics demo window',NIL,1,NIL)
  6250.        IF wptr  /* Check to see we opened a window */
  6251.          Colour(1,3)
  6252.          TextF(20,30,'Hello World')
  6253.          SetTopaz(11)
  6254.          TextF(20,60,'Hello World')
  6255.          FOR i:=10 TO 150 STEP 8  /* Plot a few points */
  6256.            Plot(i,40,2)
  6257.          ENDFOR
  6258.          Line(160,40,160,70,3)
  6259.          Line(160,70,170,40,2)
  6260.          Box(10,75,160,85,1)
  6261.          WHILE WaitIMessage(wptr)<>IDCMP_CLOSEWINDOW
  6262.          ENDWHILE
  6263.          CloseW(wptr)
  6264.        ELSE
  6265.          WriteF('Error -- could not open window!\n')
  6266.        ENDIF
  6267.      ENDPROC
  6268.  
  6269. First of all a small window is opened with a close gadget and activated
  6270. (so it is the selected window).  Clicks on the close gadget will be
  6271. reported via IDCMP, and this is the only way to quit the program.  The
  6272. graphics functions are used as follows:
  6273.  
  6274.    *     Colour is used to set the foreground colour to pen one and the
  6275.      background colour to pen three.  This will make the text nicely
  6276.      highlighted.
  6277.  
  6278.    * Text is output in the standard font.
  6279.  
  6280.    * The font is set to Topaz 11.
  6281.  
  6282.    * More text is output (probably now in a different font).
  6283.  
  6284.    * The FOR loop plots a dotted line in pen two.
  6285.  
  6286.    * A vertical line in pen three is drawn.
  6287.  
  6288.    * A diagonal line in pen two is drawn.  This and the previous line
  6289.      together produce a vee shape.
  6290.  
  6291.    * A filled box is drawn in pen one.
  6292.  
  6293. ========================================================================
  6294.  
  6295.  
  6296. Screens
  6297. =======
  6298.  
  6299.    This next example uses parts of the previous example, but also opens a
  6300. custom screen.  Basically, it draws coloured lines and boxes in a big
  6301. window opened on a 16 colour, high resolution screen.
  6302.  
  6303.      MODULE 'intuition/intuition', 'graphics/view'
  6304.      
  6305.      PROC main()
  6306.        DEF sptr=NIL, wptr=NIL, i
  6307.        sptr:=OpenS(640,200,4,V_HIRES,'Screen demo')
  6308.        IF sptr
  6309.          wptr:=OpenW(0,20,640,180,IDCMP_CLOSEWINDOW,
  6310.                      WFLG_CLOSEGADGET OR WFLG_ACTIVATE,
  6311.                      'Graphics demo window',sptr,$F,NIL)
  6312.          IF wptr
  6313.            TextF(20,20,'Hello World')
  6314.            FOR i:=0 TO 15  /* Draw a line and box in each colour */
  6315.              Line(20,30,620,30+(7*i),i)
  6316.              Box(10+(40*i),140,30+(40*i),170,1)
  6317.              Box(11+(40*i),141,29+(40*i),169,i)
  6318.            ENDFOR
  6319.            WHILE WaitIMessage(wptr)<>IDCMP_CLOSEWINDOW
  6320.            ENDWHILE
  6321.            WriteF('Program finished successfully\n')
  6322.          ELSE
  6323.            WriteF('Could not open window\n')
  6324.          ENDIF
  6325.        ELSE
  6326.          WriteF('Could not open screen\n')
  6327.        ENDIF
  6328.        IF wptr THEN CloseW(wptr)
  6329.        IF sptr THEN CloseS(sptr)
  6330.      ENDPROC
  6331.  
  6332. As you can see, the error-checking IF blocks can make the program hard to
  6333. read.  Here's the same example written with an exception handler:
  6334.  
  6335.      MODULE 'intuition/intuition', 'graphics/view'
  6336.      
  6337.      ENUM NO_ERR, WIN, SCRN
  6338.      
  6339.      RAISE WIN  IF OpenW()=NIL,
  6340.            SCRN IF OpenS()=NIL
  6341.      
  6342.      PROC main() HANDLE
  6343.        DEF sptr=NIL, wptr=NIL, i
  6344.        sptr:=OpenS(640,200,4,V_HIRES,'Screen demo')
  6345.        wptr:=OpenW(0,20,640,180,IDCMP_CLOSEWINDOW,
  6346.                    WFLG_CLOSEGADGET OR WFLG_ACTIVATE,
  6347.                    'Graphics demo window',sptr,$F,NIL)
  6348.        TextF(20,20,'Hello World')
  6349.        FOR i:=0 TO 15  /* Draw a line and box in each colour */
  6350.          Line(20,30,620,30+(7*i),i)
  6351.          Box(10+(40*i),140,30+(40*i),170,1)
  6352.          Box(11+(40*i),141,29+(40*i),169,i)
  6353.        ENDFOR
  6354.        WHILE WaitIMessage(wptr)<>IDCMP_CLOSEWINDOW
  6355.        ENDWHILE
  6356.        Raise(NO_ERR)
  6357.      EXCEPT
  6358.        IF wptr THEN CloseW(wptr)
  6359.        IF sptr THEN CloseS(sptr)
  6360.        SELECT exception
  6361.        CASE NO_ERR
  6362.          WriteF('Program finished successfully\n')
  6363.        CASE WIN
  6364.          WriteF('Could not open window\n')
  6365.        CASE SCRN
  6366.          WriteF('Could not open screen\n')
  6367.        ENDSELECT
  6368.      ENDPROC
  6369.  
  6370. It's much easier to see what's going on here.  The real part of the
  6371. program (the bit before the EXCEPT) is no longer cluttered with error
  6372. checking, and it's easy to see what happens if an error occurs.  Notice
  6373. that if the program successfully finishes it still has to close the screen
  6374. and window properly, so it's often sensible to raise a dummy exception
  6375. (like NO_ERR) and deal with all the tidying up in the handler.
  6376.  
  6377. ========================================================================
  6378.  
  6379.  
  6380. Recursion Example
  6381. *****************
  6382.  
  6383.    This next example uses a pair of mutually recursive procedures to draw
  6384. what is known as a dragon curve (a pretty, space-filling pattern).
  6385.  
  6386.      MODULE 'intuition/intuition', 'graphics/view'
  6387.      
  6388.      /* Screen size, use SIZEY=512 for a PAL screen */
  6389.      CONST SIZEX=640, SIZEY=400
  6390.      
  6391.      /* Exception values */
  6392.      ENUM NO_ERR, WIN, SCRN, STK, BRK
  6393.      
  6394.      /* Directions (DIRECTIONS gives number of directions) */
  6395.      ENUM NORTH, EAST, SOUTH, WEST, DIRECTIONS
  6396.      
  6397.      RAISE WIN  IF OpenW()=NIL,
  6398.            SCRN IF OpenS()=NIL
  6399.      
  6400.      /* Start off pointing WEST */
  6401.      DEF state=WEST, x, y, t
  6402.      
  6403.      /* Face left */
  6404.      PROC left()
  6405.        state:=Mod(state-1+DIRECTIONS, DIRECTIONS)
  6406.      ENDPROC
  6407.      
  6408.      /* Move right, changing the state */
  6409.      PROC right()
  6410.        state:=Mod(state+1, DIRECTIONS)
  6411.      ENDPROC
  6412.      
  6413.      /* Move in the direction we're facing */
  6414.      PROC move()
  6415.        SELECT state
  6416.        CASE NORTH; draw(0,t)
  6417.        CASE EAST;  draw(t,0)
  6418.        CASE SOUTH; draw(0,-t)
  6419.        CASE WEST;  draw(-t,0)
  6420.        ENDSELECT
  6421.      ENDPROC
  6422.      
  6423.      /* Draw and move to specified relative position */
  6424.      PROC draw(dx, dy)
  6425.        /* Check the line will be drawn within the window bounds */
  6426.        IF (x>=Abs(dx)) AND (x<=SIZEX-Abs(dx)) AND
  6427.           (y>=Abs(dy)) AND (y<=SIZEY-10-Abs(dy))
  6428.          Line(x, y, x+dx, y+dy, 2)
  6429.        ENDIF
  6430.        x:=x+dx
  6431.        y:=y+dy
  6432.      ENDPROC
  6433.      
  6434.      PROC main() HANDLE
  6435.        DEF sptr=NIL, wptr=NIL, i, m
  6436.        /* Read arguments:        [m [t [x  [y]]]] */
  6437.        /* so you can say: dragon  16              */
  6438.        /*             or: dragon  16 1            */
  6439.        /*             or: dragon  16 1 450        */
  6440.        /*             or: dragon  16 1 450 100    */
  6441.        /* m is depth of dragon, t is length of lines */
  6442.        /* (x,y) is the start position */
  6443.        m:=Val(arg, {i})
  6444.        t:=Val(arg:=arg+i, {i})
  6445.        x:=Val(arg:=arg+i, {i})
  6446.        y:=Val(arg:=arg+i, {i})
  6447.        /* If m or t is zero use a more sensible default */
  6448.        IF m=0 THEN m:=5
  6449.        IF t=0 THEN t:=5
  6450.        sptr:=OpenS(SIZEX,SIZEY,4,V_HIRES OR V_LACE,'Dragon Curve Screen')
  6451.        wptr:=OpenW(0,10,SIZEX,SIZEY-10,
  6452.                    IDCMP_CLOSEWINDOW,WFLG_CLOSEGADGET,
  6453.                    'Dragon Curve Window',sptr,$F,NIL)
  6454.        /* Draw the dragon curve */
  6455.        dragon(m)
  6456.        WHILE WaitIMessage(wptr)<>IDCMP_CLOSEWINDOW
  6457.        ENDWHILE
  6458.        Raise(NO_ERR)
  6459.      EXCEPT
  6460.        IF wptr THEN CloseW(wptr)
  6461.        IF sptr THEN CloseS(sptr)
  6462.        SELECT exception
  6463.        CASE NO_ERR
  6464.          WriteF('Program finished successfully\n')
  6465.        CASE WIN
  6466.          WriteF('Could not open window\n')
  6467.        CASE SCRN
  6468.          WriteF('Could not open screen\n')
  6469.        CASE STK
  6470.          WriteF('Ran out of stack in recursion\n')
  6471.        CASE BRK
  6472.          WriteF('User aborted\n')
  6473.        ENDSELECT
  6474.      ENDPROC
  6475.      
  6476.      /* Draw the dragon curve (with left) */
  6477.      PROC dragon(m)
  6478.        /* Check stack and ctrl-C before recursing */
  6479.        IF FreeStack()<1000 THEN Raise(STK)
  6480.        IF CtrlC() THEN Raise(BRK)
  6481.        IF m>0
  6482.          dragon(m-1)
  6483.          left()
  6484.          nogard(m-1)
  6485.        ELSE
  6486.          move()
  6487.        ENDIF
  6488.      ENDPROC
  6489.      
  6490.      /* Draw the dragon curve (with right) */
  6491.      PROC nogard(m)
  6492.        IF m>0
  6493.          dragon(m-1)
  6494.          right()
  6495.          nogard(m-1)
  6496.        ELSE
  6497.          move()
  6498.        ENDIF
  6499.      ENDPROC
  6500.  
  6501.    If you write this to the file dragon.e and compile it to the executable
  6502. dragon then some good things to try are:
  6503.  
  6504.      dragon 5 9 300 100
  6505.      dragon 10 4 250 250
  6506.      dragon 11 3 250 250
  6507.      dragon 15 1 300 100
  6508.      dragon 16 1 400 150
  6509.  
  6510.    If you want to understand how the program works you need to study the
  6511. recursive parts.  Here's an overview of the program, outlining the
  6512. important aspects:
  6513.  
  6514.    * The constants SIZEX and SIZEY are the width and height (respectively)
  6515.      of the custom screen (and window).  As the comment suggests, change
  6516.      SIZEY to 512 if you want a bigger screen and you have a PAL Amiga.
  6517.  
  6518.    * The state variable holds the current direction (north, south, east or
  6519.      west).
  6520.  
  6521.    * The left and right procedures turn the current direction to the left
  6522.      and right (respectively) by using some modulo arithmetic trickery.
  6523.  
  6524.    * The move procedure uses the draw procedure to draw a line (of length
  6525.      t) in the current direction from the current point (stored in x
  6526.      and y).
  6527.  
  6528.    * The draw procedure draws a line relative to the current point, but
  6529.      only if it fits within the boundaries of the window.  The current
  6530.      point is moved to the end of the line (even if it isn't drawn).
  6531.  
  6532.    * The main procedure reads the command line arguments into the
  6533.      variables m, t, x and y.  The depth/size of the dragon is given by m
  6534.      (the first argument) and the length of each line making up the dragon
  6535.      is given by t (the second argument).  The starting point is given by
  6536.      x and y (the final two arguments).  The defaults are five for m
  6537.      and t, and zero for x and y.
  6538.  
  6539.    * The main procedure also opens the screen and window, and sets the
  6540.      dragon drawing.
  6541.  
  6542.    * The dragon and nogard procedures are very similar, and these are
  6543.      responsible for creating the dragon curve by calling the left, right
  6544.      and move procedures.
  6545.  
  6546.    * The dragon procedure contains a couple of checks to see if the user
  6547.      has pressed Control-C or if the program has run out of stack space,
  6548.      raising an appropriate exception if necessary.  These exceptions are
  6549.      handled by the main procedure.
  6550.  
  6551. Notice the use of Val and the exception handling.  Also, the important
  6552. base case of the recursion is when m reaches zero (or becomes negative,
  6553. but that shouldn't happen).  If you start off a big dragon and want to
  6554. stop it you can press Control-C and the program tidies up nicely.  If it
  6555. has finished drawing you simply click the close gadget on the window.
  6556.  
  6557. ========================================================================
  6558.  
  6559.  
  6560. Common Problems
  6561. ***************
  6562.  
  6563.    If you are new to programming or the Amiga E language then you might
  6564. appreciate some help locating problems (or bugs) in your programs.  This
  6565. Appendix details some of the most common mistakes people make.
  6566.  
  6567. Next:
  6568.  
  6569.   Assignment and Copying  
  6570.   Pointers and Memory Allocation  
  6571.   String and List Misuse  
  6572.   Initialising Data  
  6573.   Freeing Resources  
  6574.   Array and Object Element Selection  
  6575.   Pointers and Dereferencing  
  6576.  
  6577. ========================================================================
  6578.  
  6579.  
  6580. Assignment and Copying
  6581. ======================
  6582.  
  6583.    This is probably the most common problem encountered by people who are
  6584. used to languages like BASIC.  Things like E-strings or arrays cannot be
  6585. initialised using an assignment statement: data must be copied.  This
  6586. means that you shouldn't write this:
  6587.  
  6588.      /* You probably don't want to do this */
  6589.        DEF s[30]:STRING, a[25]:ARRAY OF INT
  6590.        s:='Some text in a string'
  6591.        a:=[1,-3,8,7]:INT
  6592.  
  6593. Instead you need to copy the string constant and array data, like this:
  6594.  
  6595.        DEF s[30]:STRING, a[25]:ARRAY OF INT
  6596.        StrCopy(s,'Some text in a string',ALL)
  6597.        CopyMem([1,-3,8,7]:INT, a, 4*2)
  6598.  
  6599. The CopyMem function is an Amiga system function from the Exec library.
  6600. It does a byte-by-byte copy, something like this:
  6601.  
  6602.      PROC copymem(src, dest, size)
  6603.        DEF i
  6604.        FOR i:=1 TO size DO dest[]++:=src[]++
  6605.      ENDPROC
  6606.  
  6607.    Of course, you can use string constants and typed lists to give
  6608. initialised arrays, but in this case you should be initialising an
  6609. appropriately typed pointer.  You must also be careful not to run into a
  6610. static data problem (see Static data).
  6611.  
  6612.        DEF s:PTR TO CHAR, a:PTR TO INT
  6613.        s:='Some text in a string'
  6614.        a:=[1,-3,8,7]:INT
  6615.  
  6616. ========================================================================
  6617.  
  6618.  
  6619. Pointers and Memory Allocation
  6620. ==============================
  6621.  
  6622.    Another common error is to declare a pointer (usually a pointer to an
  6623. object) and then use it without the memory for the target data being
  6624. allocated.
  6625.  
  6626.      /* You don't want to do this */
  6627.        DEF p:PTR TO object
  6628.        p.element:=99
  6629.  
  6630. There are two ways of correcting this: either dynamically allocate the
  6631. memory using New or, more simply, let an appropriate declaration allocate
  6632. it.
  6633.  
  6634.        DEF p:PTR TO object
  6635.        p:=New(SIZEOF object)
  6636.      
  6637.        DEF p:object
  6638.        p.element:=99
  6639.  
  6640. ========================================================================
  6641.  
  6642.  
  6643. String and List Misuse
  6644. ======================
  6645.  
  6646.    Some of the string functions can only be used with E-strings.
  6647. Generally, these are the ones that might extend the string.  If you use a
  6648. normal string instead you can run into some serious (but subtle) problems.
  6649. Commonly misused functions are ReadStr, MidStr and RightStr.  Similar
  6650. problems can arise by using a list when an E-list is required by a list
  6651. function.
  6652.  
  6653.    String constants and normal lists are static data, so you shouldn't try
  6654. to alter their contents unless you know what you're doing (see
  6655. Static data).
  6656.  
  6657. ========================================================================
  6658.  
  6659.  
  6660. Initialising Data
  6661. =================
  6662.  
  6663.    Probably one of the most common mistakes that even seasoned programmers
  6664. make is to forget to initialise variables (especially pointers).  The
  6665. rules in the `Reference Manual' state which declarations initialise
  6666. variables to zero values, but it is often wise to make even these explicit
  6667. (using initialised declarations).  Variable initialisation becomes even
  6668. more important when using automatic exceptions.
  6669.  
  6670. ========================================================================
  6671.  
  6672.  
  6673. Freeing Resources
  6674. =================
  6675.  
  6676.    Unlike most Unix systems, the Amiga operating system requires the
  6677. programmer to release or free any resources used by a program.  In
  6678. practice, this means that all windows, screens, libraries, etc., that are
  6679. successfully opened must be closed before the program terminates.  Amiga E
  6680. provides some help, though: the four most commonly used libraries (Dos,
  6681. Exec, Graphics and Intuition) are opened before the start of an E program
  6682. and closed at the end (or when CleanUp is called).  Also, memory allocated
  6683. using New, List and String is automatically freed at the end of a program.
  6684.  
  6685. ========================================================================
  6686.  
  6687.  
  6688. Array and Object Element Selection
  6689. ==================================
  6690.  
  6691.    A lot of programmers who are used to languages like C try to use
  6692. multiple object element selection.  Amiga E only allows one level of
  6693. object element selection.  These same concerns apply to arrays, and
  6694. mixtures of arrays and objects.  See Element types.
  6695.  
  6696.    Assignment expressions can also cause problems: they do not allow as
  6697. rich a left-hand side as assignment statements.  See Assignments.
  6698.  
  6699. ========================================================================
  6700.  
  6701.  
  6702. Pointers and Dereferencing
  6703. ==========================
  6704.  
  6705.    C programmers may think that the  ^var and {var } expressions are the
  6706. direct equivalent of C's  &var and  *var expressions.  However, in E
  6707. dereferencing is normally achieved using array and object element
  6708. selection, and pointers to large amounts of data (like E-strings or
  6709. objects) are made by declarations.  This means that the  ^var and {var }
  6710. expressions are rarely used, whilst var[] is very common.
  6711.  
  6712. ========================================================================
  6713.  
  6714.  
  6715. New Features
  6716. ************
  6717.  
  6718.    This Appendix introduces a few of the new features of Amiga E version
  6719. 3.0.  This is only rough information, see the `Reference Manual' for more
  6720. details.
  6721.  
  6722. Next:
  6723.  
  6724.   Default Arguments  
  6725.   Multiple Return Values  
  6726.   NEW Operator  
  6727.   Object Inheritance  
  6728.   Code Modules  
  6729.   SELECT OF Statement  
  6730.  
  6731. ========================================================================
  6732.  
  6733.  
  6734. Default Arguments
  6735. =================
  6736.  
  6737.    Procedures can now be defined to have default arguments.  This means
  6738. that a call to the procedure can leave out some of the parameters and they
  6739. will filled in with default values.  For instance,
  6740.  
  6741.      PROC fred(a,b,c=2,d=TRUE)
  6742.  
  6743. declares the procedure fred as normal, but the last two parameters can
  6744. take defaults.  This means fred(3,4) is allowed, and it means the same as
  6745. fred(3,4,1,TRUE).  Also, fred(3,4,5) is allowed, and this means the same
  6746. as fred(3,4,5,TRUE).
  6747.  
  6748.    Only the right-hand parameters can be defaulted, and the parameters
  6749. that are supplied when calling the procedure are taken to be as many of
  6750. the left-hand parameters as possible.  This means, in the fred example,
  6751. you can't leave out the c parameter if you want to supply the d parameter,
  6752. and you can't make the a parameter have a default without making b also
  6753. have a default.
  6754.  
  6755.    Default arguments are especially useful for the built-in functions.
  6756. For instance, you normally use StrCopy with the final parameter being ALL.
  6757. In version 3.0 of Amiga E, this parameter defaults to ALL so you can write
  6758. StrCopy(s,t) to copy the contents of string t to s, instead of
  6759. StrCopy(s,t,ALL).
  6760.  
  6761. ========================================================================
  6762.  
  6763.  
  6764. Multiple Return Values
  6765. ======================
  6766.  
  6767.    Version 3.0 of Amiga E allows RETURN and ENDPROC to return up to three
  6768. values.  The first of these is considered to be the main return value, is
  6769. the value of the procedure call expression.  However, when the procedure
  6770. call is used directly with an assignment statement you can extract any
  6771. number of the return values.  For example, the following procedure returns
  6772. the values of x and y, which are calculated from the parameters a and b.
  6773. The main return value is x since it is the first return value.
  6774.  
  6775.      PROC exandwhy(a,b)
  6776.        DEF x,y
  6777.        x:=a*b
  6778.        y:=a+b
  6779.      ENDPROC x,y
  6780.  
  6781. You can call this procedure in the following ways:
  6782.  
  6783.        DEF p,q
  6784.        p:=exandwhy(3,4)
  6785.        p,q:=exandwhy(3,4)
  6786.        p:=(8*exandwhy(3,4))
  6787.  
  6788. The first assignment assigns the value of x (i.e., 3*4) to p, since x is
  6789. the first return value.  The second assignment uses both of the returns
  6790. values: it assigns x to p, and y to q.  The third assignment has the call
  6791. to exandwhy in an expression so only the x value is used, and in this case
  6792. you can't get the y value so you can't assign to both p and q.
  6793.  
  6794.    Again, this is useful for one of the built-in functions.  Val normally
  6795. needs the address of a variable as its second parameter so that the number
  6796. of characters read can be discovered as well as the value of the string.
  6797. In version 3.0 of Amiga E Val has two return values.  The first is the
  6798. value of the supplied string and the second is the number of characters
  6799. read.  So this code fragment in version 3.0,
  6800.  
  6801.        DEF v, num, s
  6802.        s:='-232 22'
  6803.        v, num:=Val(s)
  6804.  
  6805. is equivalent to:
  6806.  
  6807.        DEF v, num, s
  6808.        s:='-232 22'
  6809.        v:=Val(s, {num})
  6810.  
  6811. ========================================================================
  6812.  
  6813.  
  6814. NEW Operator
  6815. ============
  6816.  
  6817.    The NEW operator allows for typed memory allocation.  Basically, if you
  6818. have a pointer p which has been declared to be PTR TO type, then NEW p
  6819. allocates a chunk of memory to hold something from type, stores a pointer
  6820. to this memory in p and returns this pointer.  If the memory could not be
  6821. allocated the exception "NEW" is raised.
  6822.  
  6823.    The following program (where rec is some object definition):
  6824.  
  6825.      PROC main()
  6826.        DEF p:PTR TO rec
  6827.        NEW p
  6828.      ENDPROC
  6829.  
  6830. is equivalent to:
  6831.  
  6832.      RAISE "NEW" IF New()=NIL
  6833.      
  6834.      PROC main()
  6835.        DEF p:PTR TO rec
  6836.        p:=New(SIZEOF rec)
  6837.      ENDPROC
  6838.  
  6839.    You can also use NEW to dynamically allocate an array:
  6840.  
  6841.        DEF a:PTR TO INT
  6842.        NEW a[10]
  6843.  
  6844. This allocates a new array of ten integers and is basically equivalent to
  6845. the following array declaration, except the NEW form can be repeated with
  6846. different sizes and doesn't restrict you to declarations.
  6847.  
  6848.        DEF a[10]:ARRAY OF INT
  6849.  
  6850.    Yet more power comes when you use lists and typed lists.  As mentioned
  6851. earlier, these structures are static (see Static data).  Well, the NEW
  6852. operator turns them into dynamic structures.  Remember this example:
  6853.  
  6854.      PROC main()
  6855.        DEF i, a[10]:ARRAY OF LONG, p:PTR TO LONG
  6856.        FOR i:=0 TO 9
  6857.          a[i]:=[1, i, i*i]
  6858.            /* This assignment is probably not what you want! */
  6859.        ENDFOR
  6860.        FOR i:=0 TO 9
  6861.          p:=a[i]
  6862.          WriteF('a[\d] is an array at address \d\n', i, p)
  6863.          WriteF('  and the second element is \d\n', p[1])
  6864.        ENDFOR
  6865.      ENDPROC
  6866.  
  6867. We can now cure the problem very simply using NEW:
  6868.  
  6869.      PROC main()
  6870.        DEF i, a[10]:ARRAY OF LONG, p:PTR TO LONG
  6871.        FOR i:=0 TO 9
  6872.          a[i]:=NEW [1, i, i*i]
  6873.        ENDFOR
  6874.        FOR i:=0 TO 9
  6875.          p:=a[i]
  6876.          WriteF('a[\d] is an array at address \d\n', i, p)
  6877.          WriteF('  and the second element is \d\n', p[1])
  6878.        ENDFOR
  6879.      ENDPROC
  6880.  
  6881.    The memory allocated by NEW is freed when the program terminates, but
  6882. you can free it beforehand (if you must) using the Dispose functions in
  6883. the normal way (see System support functions).  The exceptions to this are
  6884. lists and typed lists (which are not normally freed since they are static).
  6885. See the `Reference Manual' for details about how to free these things.
  6886.  
  6887. ========================================================================
  6888.  
  6889.  
  6890. Object Inheritance
  6891. ==================
  6892.  
  6893.    Object inheritance allows you to make objects from other objects
  6894. without nesting the objects.  The normal way of using objects needs
  6895. intermediate pointers to access objects within an object.  Consider the
  6896. following object definitions:
  6897.  
  6898.      OBJECT fullname
  6899.        firstname, surname
  6900.      ENDOBJECT
  6901.      
  6902.      OBJECT person
  6903.        name : fullname,
  6904.        address,
  6905.        telephone
  6906.      ENDOBJECT
  6907.  
  6908. If p was of type person then to access the surname you need to do the
  6909. following:
  6910.  
  6911.        DEF q:PTR TO fullname, s
  6912.        q:=p.name
  6913.        s:=q.surname
  6914.  
  6915. So, we need to have an intermediate pointer q to get s to point to the
  6916. surname.
  6917.  
  6918.    With object inheritance you can use the OF keyword with an object
  6919. definition like this:
  6920.  
  6921.      OBJECT fullname
  6922.        firstname, surname
  6923.      ENDOBJECT
  6924.      
  6925.      OBJECT person OF fullname
  6926.        address,
  6927.        telephone
  6928.      ENDOBJECT
  6929.  
  6930. Now the object fullname is inherited by the object person, and the surname
  6931. part of p (a pointer to person) is simply p.surname.
  6932.  
  6933.    The main use of this feature is for relating objects and reusing code.
  6934. Someone can define a small collection of useful objects and procedures
  6935. which operate on these objects, and you can incorporate their objects into
  6936. yours and reuse their procedures.  We've already seen a silly example
  6937. where the person object incorporates the fullname object, so now consider
  6938. the following procedure which nicely prints a name:
  6939.  
  6940.      PROC printname(p:PTR TO fullname)
  6941.        WriteF('Hello, \s \s\n', p.firstname, p.surname)
  6942.      ENDPROC
  6943.  
  6944. This procedure requires a fullname object as a parameter, but is just as
  6945. happy if you supply a person object.  In this case, only the fullname
  6946. elements of the person object will be affected by the procedure.  Here's a
  6947. couple of examples which call printname:
  6948.  
  6949.        DEF name, barney
  6950.      
  6951.        name:=['Barney', 'Rubble']:fullname
  6952.        printname(name)
  6953.      
  6954.        barney:=['Barney', 'Rubble', 'Rockville', '80085']:person
  6955.        printname(barney)
  6956.  
  6957. ========================================================================
  6958.  
  6959.  
  6960. Code Modules
  6961. ============
  6962.  
  6963.    In version 2.1 modules could contain only constant and object
  6964. definitions, and library descriptions.  With version 3.0 you can also have
  6965. procedure definitions and some global variables.  To make a module
  6966. containing such definitions you use the E compiler as you would to make an
  6967. executable, but in this case you use the statement OPT MODULE at the start
  6968. of the code.  Also, all definitions that are to be accessed from outside
  6969. the module need to be marked with the EXPORT keyword.  Alternatively, all
  6970. definitions can be exported using OPT EXPORT at the start of the code.
  6971. You include the definitions from this module (and use the exported ones)
  6972. in your program using MODULE in the normal way.
  6973.  
  6974.    The following code is an example of a small module:
  6975.  
  6976.      OPT MODULE
  6977.      
  6978.      EXPORT CONST MAX_LEN=20
  6979.      
  6980.      EXPORT OBJECT fullname
  6981.        firstname, surname
  6982.      ENDOBJECT
  6983.      
  6984.      EXPORT PROC printname(p:PTR TO fullname)
  6985.        IF short(p.surname)
  6986.          WriteF('Hello, \s \s\n', p.firstname, p.surname)
  6987.        ELSE
  6988.          WriteF('Gosh, you have a long name\n')
  6989.        ENDIF
  6990.      ENDPROC
  6991.      
  6992.      PROC short(s)
  6993.        RETURN StrLen(s)<MAX_LEN
  6994.      ENDPROC
  6995.  
  6996. Everything is exported except the short procedure.  Therefore, this can be
  6997. accessed only in the module.  In fact, the printname procedure uses it
  6998. (rather artificially) to check the length of the surname.  It's not of
  6999. much use or interest apart from in the module, so that's why it isn't
  7000. exported.  In effect, we've hidden the fact that printname uses short from
  7001. the user of the module.
  7002.  
  7003.    Assuming the above code was compiled to module mymods/name, here's how
  7004. it could be used:
  7005.  
  7006.      MODULE 'mymods/name'
  7007.      
  7008.      PROC main()
  7009.        DEF fred:PTR TO fullname, bigname
  7010.        fred.firstname:='Fred'
  7011.        fred.surname:='Flintstone'
  7012.        printname(fred)
  7013.        bigname:=['Peter', 'Extremelybiglongprehistoricname']
  7014.        printname(bigname)
  7015.      ENDPROC
  7016.  
  7017.    Global variables in a module are a bit more problematic than the other
  7018. kinds of definitions.  You cannot initialise them in the declaration or
  7019. make them reserve chunks memory.  So you can't have ARRAY, OBJECT, STRING
  7020. or LIST declarations.  However, you can have pointers so this isn't a big
  7021. problem.  The reason for this limitation is that exported global variables
  7022. with the same name in a module and the main program are taken to be the
  7023. same variable, and the values are shared.  So you can have an array
  7024. declaration in the main program:
  7025.  
  7026.      DEF a[80]:ARRAY OF INT
  7027.  
  7028. and the appropriate pointer declaration in the module:
  7029.  
  7030.      EXPORT DEF a:PTR TO INT
  7031.  
  7032. The array from the main program can then be accessed in the module!  For
  7033. this reason you also need to be pretty careful about the names of your
  7034. exported variables so you don't get unwanted sharing.  Global variables
  7035. which are not exported are private to the module, so will not clash with
  7036. variables in the main program or other modules.
  7037.  
  7038. ========================================================================
  7039.  
  7040.  
  7041. SELECT OF Statement
  7042. ===================
  7043.  
  7044.    Basically, this is a range version of SELECT, as it allows the CASE
  7045. parts to be ranges.  It is best described by example, so here's a nice
  7046. simple one s is an array of characters:
  7047.  
  7048.        SELECT 127 OF s[i]
  7049.        CASE "\n", "\b"
  7050.          WriteF('Line end\n')
  7051.        CASE "\t", " "
  7052.          WriteF('Whitespace\n')
  7053.        CASE "0" TO "9"
  7054.          WriteF('Number\n')
  7055.        CASE "a" TO "z", "A" TO "Z"
  7056.          WriteF('Letter\n')
  7057.        DEFAULT
  7058.          WriteF('Some other character\n')
  7059.        ENDSELECT
  7060.  
  7061. The first number after the SELECT is the limit of the constants that
  7062. appear in the CASE parts (i.e., 127 in the example since we are checking
  7063. ASCII character values).  If the value given is n then the constants in
  7064. the CASE parts must be between zero and n if the SELECT is to work
  7065. properly.
  7066.  
  7067.    The expression after the OF on the SELECT line is the value which is
  7068. being checked.  Notice that this can be any expression, whereas in a
  7069. SELECT statement you can use only a variable.  On the other hand, the
  7070. CASE parts of a SELECT statement can be expressions, but in a SELECT OF
  7071. they must be constants or a range given by two constants.
  7072.  
  7073.    In the example, the line:
  7074.  
  7075.        CASE "\n", "\b"
  7076.  
  7077. matches a linefeed or a carriage return character, and the lines of code
  7078. for this CASE part will be executed if s[i] is either of these values.
  7079. The line:
  7080.  
  7081.        CASE "0" TO "9"
  7082.  
  7083. matches any of the characters 0, 1, 2, 3, 4, 5, 6, 7, 8 and 9.
  7084.  
  7085.    The DEFAULT case will be used if s[i] matches none of the CASE parts,
  7086. and if it is outside the limiting range (i.e, zero to 127 in the example).
  7087.  
  7088.    Be careful not to make the maximum range value too big, because the
  7089. compiler generates code which makes a table twice that size in order for
  7090. the SELECT OF to work efficiently.  So, if you say SELECT 100000 OF x you
  7091. can expect the executable to be pretty big.  Therefore, this statement is
  7092. useful only for small ranges.
  7093.  
  7094. ========================================================================
  7095.  
  7096.  
  7097. Syntax Description
  7098. ******************
  7099.  
  7100.    Wouter has written a description of the E syntax in BNF form.  This
  7101. description refers to features added in version 3.0, but it is still
  7102. applicable to previous versions (ignoring these additions!).  It is hoped
  7103. that the more advanced user will find this a useful reference, since it
  7104. gives a more detailed description of the grammar and syntax of E in a
  7105. concise form.  However, it is not guaranteed to be complete.
  7106.  
  7107. Next:
  7108.  
  7109.   Lex Syntax  
  7110.   Parse Syntax  
  7111.  
  7112. ========================================================================
  7113.  
  7114.  
  7115. Lex Syntax
  7116. ==========
  7117.  
  7118.    The Lex syntax describes the characters or sequences of characters
  7119. which are allowed for certain objects.  The syntax used is that of regular
  7120. expressions.  For instance, space and tab characters are valid whitespace,
  7121. built-in procedures begin with an uppercase letter followed by a lowercase
  7122. letter, and user-defined identifiers (variable, procedure and object
  7123. names) must begin with a lowercase letter.
  7124.  
  7125.      +-------------------+
  7126.      |       LEX         |
  7127.      +-------------------+
  7128.      
  7129.      lex syntax: regular expressions
  7130.      
  7131.      +-------------------+
  7132.      
  7133.      whitespace      = [ \t]      ; also \n if last token is [,+-*/] or similar
  7134.                        anything between "/*" and "*/"
  7135.                        from "->" to \n
  7136.      eol             = [;\n]
  7137.      
  7138.      constant        = [A-Z] ( [A-Z] [A-Za-z0-9_]* )?
  7139.      builtin         = [A-Z] [a-z] [A-Za-z0-9_]*
  7140.      ident,objident  = [a-z] [a-zA-Z0-9_]*
  7141.      
  7142.      num             = [0-9]+     ; "-" is separate token
  7143.                        $[0-9A-Fa-f]+
  7144.                        %[01]+
  7145.      fnum            = [0-9]*.[0-9]*
  7146.      
  7147.      stringconst     = anything in ''
  7148.      charconst       = anything in ""
  7149.  
  7150. ========================================================================
  7151.  
  7152.  
  7153. Parse Syntax
  7154. ============
  7155.  
  7156.    The parse syntax describes syntax of E. It is a variation on standard
  7157. BNF, and is described below.  For instance, there are six different kinds
  7158. of multi-line statements: the IF block, FOR loop, WHILE loop,
  7159. REPEAT..UNTIL loop, SELECT block and LOOP block.  The WHILE loop
  7160. consists of the WHILE keyword followed by an expression (the loop check),
  7161. an end-of-line separator (usually a newline), some statements, then the
  7162. ENDWHILE keyword.
  7163.  
  7164.      +-------------------+
  7165.      |       PARSE       |
  7166.      +-------------------+
  7167.      
  7168.      parse syntax: own ASF/SDF adaptation;
  7169.      
  7170.              name    = grammar ident
  7171.              "name"  = constant
  7172.              ()      = grouping
  7173.              |       = or
  7174.              e*      = 0 or more of e
  7175.              e+      = 1 or more of e
  7176.              {e s}*  = 0 or more of e separated by s
  7177.              {e s}+  = 1 or more of e separated by s
  7178.              [e]     = e is optional
  7179.              ; e     = e is comment :-)
  7180.      
  7181.      +-------------------+
  7182.      
  7183.      program     ::= opts globalpart localpart
  7184.      
  7185.      globalpart  ::= ( modulestat | defstat | objdecl | constdecl | raisedecl )*
  7186.      localpart   ::= ( procdecl | constdecl )+
  7187.      
  7188.      modulestat  ::= "MODULE" { conststring "," }+ eol
  7189.      defstat     ::= "DEF" vardecllist eol
  7190.      objdecl     ::= "OBJECT" ident [ "OF" ident ] eol
  7191.                         ( vardecllist eol )+
  7192.                      "ENDOBJECT" eol
  7193.      constdecl   ::= "CONST" { ( constant "=" constexp ) "," }+
  7194.                   |  "ENUM" { ( constant | constant "=" constexp ) "," }+
  7195.                   |  "SET" { constant "," }+
  7196.      procdecl    ::= [ "EXPORT" ] "PROC" ident "(" argdecllist ")" [ "HANDLE" ]
  7197.                       (   "RETURN" { exp "," }*
  7198.                         | eol defstat* stats
  7199.                           [ "EXCEPT" eol stats ]
  7200.                           "ENDPROC" { exp "," }* eol )
  7201.      raisedecl   ::= "RAISE" { ( constant "IF" builtin "()" compop num ) "," }+
  7202.      opts        ::= ( "OPT" { setting "," }+ )*           ; machine dependent
  7203.      
  7204.      vardecllist ::= { vardecl "," }+
  7205.      vardecl     ::= ident [ "=" num ]
  7206.                        [ ":" ( "LONG" | "REAL" | "PTR" "TO" ptrtype ) ]
  7207.                   |  ident ":" objtype
  7208.                   |  ident "[" num "]" ":"
  7209.                        (   "ARRAY"
  7210.                          | "ARRAY" "OF" ptrtype
  7211.                          | "STRING"
  7212.                          | "LIST" )
  7213.      argdecllist ::= { argdecl "," }+
  7214.      argdecl     ::= ident [ "=" defaultarg ]
  7215.                        [ ":" ( "LONG" | "REAL" | "PTR" "TO" ptrtype ) ]
  7216.      ptrtype     ::= objtype | simpletype
  7217.      simpletype  ::= CHAR | INT | LONG
  7218.      objtype     ::= ident
  7219.      
  7220.      stats       ::= ( ( onelinestat | multlinestat ) eol )*
  7221.      onelinestat ::= exp
  7222.                   |  lval ":=" exp
  7223.                   |  { var "," }+ ":=" exp
  7224.                   |  "IF" exp "THEN" onelinestat "ELSE" onelinestat
  7225.                   |  "FOR" var ":=" exp "TO" exp [ "STEP" num ]
  7226.                         "DO" onelinestat
  7227.                   |  "WHILE" exp "DO" onelinestat
  7228.                   |  "RETURN" { exp "," }*
  7229.                   |  "JUMP" ident
  7230.                   |  ( "INC" | "DEC" ) var               ; nearly obsolete
  7231.                   |  asm_mnemonic { operand "," }*       ; machine dependent
  7232.                   |  "INCBIN" stringconst                ; inline asm support
  7233.                   |  simpletype { num "," }+
  7234.                   |  "VOID" exp                          ; obsolete
  7235.      multlinestat ::= "IF" exp eol stats
  7236.                          [ ( "ELSEIF" exp eol stats )* ]
  7237.                          [ "ELSE" eol stats ]
  7238.                          "ENDIF"
  7239.                   |  "FOR" var ":=" exp "TO" exp [ "STEP" num ] eol
  7240.                         stats "ENDPROC"
  7241.                   |  "WHILE" exp eol stats "ENDWHILE"
  7242.                   |  "REPEAT" eol stats "UNTIL" exp
  7243.                   |  "SELECT" var eol
  7244.                         ( "CASE" exp eol stats )+
  7245.                         [ "DEFAULT" eol stats ]
  7246.                         "ENDSELECT"
  7247.                   |  "LOOP" eol stats "ENDLOOP"
  7248.      
  7249.      explist     ::= { exp "," }+
  7250.      exp         ::= [ "-" ] { item binop }+
  7251.                   |  exp "BUT" exp
  7252.      item        ::= num | fnum | lval | stringconst | charconst
  7253.                   |  "SIZEOF" objident
  7254.                   |  "IF" exp "THEN" exp "ELSE" exp
  7255.                   |  "[" explist "]" [ ":" ptrtype ]
  7256.                   |  ( builtin | ident ) "(" explist ")"
  7257.                   |  var ":=" exp
  7258.                   |  "{" ident "}"
  7259.                   |  "`" exp
  7260.      binop       ::= mathop | compop | logop
  7261.      mathop      ::= "+" | "-" | "*" | "/"
  7262.      compop      ::= "=" | "<>" | ">" | "<" | ">=" | "<="
  7263.      logop       ::= "AND" | "OR"
  7264.      constexp    ::= [ "-" ] { num ( "+" | "-" | "*" | "/" ) }+
  7265.      lval        ::= var [ "[" [ exp ] "]" ] [ "." ident ] [ "++" | "--" ]
  7266.                   |  "^" var [ "++" | "--" ] |
  7267.      var         ::= ident
  7268.      defaultarg  ::= num
  7269.  
  7270. ========================================================================
  7271.  
  7272.  
  7273. Other Information
  7274. *****************
  7275.  
  7276.    This Appendix contains some useful, miscellaneous information.
  7277.  
  7278. Next:
  7279.  
  7280.   Amiga E Versions  
  7281.   Further Reading  
  7282.   Amiga E Author  
  7283.   Guide Author  
  7284.  
  7285. ========================================================================
  7286.  
  7287.  
  7288. Amiga E Versions
  7289. ================
  7290.  
  7291.    As I write, the current version of Amiga E is version 2.1b, so this
  7292. Guide is based primarily on that version.  Version 3.0 is due to be
  7293. released soon, and the 3.0 specific information is based solely on
  7294. information from Wouter.  The next version of this Guide will hopefully
  7295. cover 3.0 in more detail.
  7296.  
  7297. ========================================================================
  7298.  
  7299.  
  7300. Further Reading
  7301. ===============
  7302.  
  7303. `Amiga E Language Reference'
  7304.      Referred to as the `Reference Manual' in this Guide.  This is one of
  7305.      the documents that comes with the Amiga E package, and is essential
  7306.      reading since it was written by Wouter (the author of Amiga E).
  7307.  
  7308. `Rom Kernel Reference Manual' (Addison-Wesley)
  7309.      This is the official Commodore documentation on the Amiga system
  7310.      functions and is a must if you want to use these functions properly.
  7311.      At the time of writing the Third Edition is the most current and it
  7312.      covers the Amiga system functions up to Release 2 (i.e., AmigaDOS
  7313.      2.04 and KickStart 37).  Because there is so much information it
  7314.      comes in three separate volumes: `Libraries', `Includes and
  7315.      Autodocs', and `Devices'.  The `Libraries' volume is probably the
  7316.      most useful as it contains many examples and a lot of tutorial
  7317.      material.  However, the examples are written mainly in C (the
  7318.      remainder are in Assembly).
  7319.  
  7320. `The AmigaDOS Manual' (Bantam Books)
  7321.      This is the companion to the `Rom Kernel Reference Manual' and is the
  7322.      official Commodore book on AmigaDOS (both the AmigaDOS programs and
  7323.      the DOS library functions).  Again, the Third Edition is the most
  7324.      current.
  7325.  
  7326. Example sources
  7327.      Amiga E comes with a large collection of example programs.  When
  7328.      you're familiar with the language you should be able to learn quite a
  7329.      bit from these.  There are a lot of small, tutorial programs and a
  7330.      few large, complicated programs.
  7331.  
  7332. ========================================================================
  7333.  
  7334.  
  7335. Amiga E Author
  7336. ==============
  7337.  
  7338.    In case you didn't know the author and creator of Amiga E is Wouter van
  7339. Oortmerssen (or $#%!).  You can reach him by normal mail at the following
  7340. address:
  7341.  
  7342.      Wouter van Oortmerssen ($#%!)
  7343.      Levendaal 87
  7344.      2311 JG  Leiden
  7345.      HOLLAND
  7346.  
  7347. However, he much prefers to chat by E-mail, and you can reach him at the
  7348. following addresses:
  7349.  
  7350.      Wouter@alf.let.uva.nl (E-programming support)
  7351.      Wouter@mars.let.uva.nl (personal)
  7352.      Oortmers@gene.fwi.uva.nl (other)
  7353.  
  7354. Better still, if your problem or enquiry is of general interest to Amiga E
  7355. users you may find it useful joining the Amiga E mailing list.  Wouter
  7356. regularly contributes to this list and there are a number of good
  7357. programmers who are at hand to help or discuss problems.  To join send a
  7358. message to:
  7359.  
  7360.      amigae-request@bkhouse.cts.com
  7361.  
  7362. Once you're subscribed, you will receive a copy of each message mailed to
  7363. the list.  You will also receive a message telling you how you can
  7364. contribute (i.e., ask questions!).
  7365.  
  7366. ========================================================================
  7367.  
  7368.  
  7369. Guide Author
  7370. ============
  7371.  
  7372.    This Guide was written by Jason Hulance, with a lot of help and
  7373. guidance from Wouter.  The original aim was to produce something that
  7374. might be a useful introduction to Amiga E for beginners, so that the
  7375. language could (rightly) become more widespread.  The hidden agenda was to
  7376. free Wouter from such a task so that he could concentrate his efforts on
  7377. producing the next (3.0) version of Amiga E.
  7378.  
  7379.    You can reach me by normal mail most easily at the following (work)
  7380. address:
  7381.  
  7382.      Jason R. Hulance
  7383.      Formal Systems (Europe) Ltd.
  7384.      3 Alfred Street
  7385.      Oxford
  7386.      OX1 4EH
  7387.      ENGLAND
  7388.  
  7389. Alternatively, you can find me on the Amiga E mailing list, or E-mail me
  7390. directly at the following address:
  7391.  
  7392.      m88jrh@uk.ac.oxford.ecs
  7393.  
  7394. If you have any changes or additions you'd like to see then I'd be very
  7395. happy to consider them.  Criticism of the text is also welcome, especially
  7396. if you can suggest a better way of explaining things.
  7397.